diff --git a/.coveragerc b/.coveragerc index d3b3b11b..9cac3c1e 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,8 @@ source = omit = # Don't worry about covering vendored libraries src/sphobjinv/_vendored/* + # Not part of the test suite + setup.py [report] exclude_lines = diff --git a/.github/workflows/all_core_tests.yml b/.github/workflows/all_core_tests.yml index 96935961..686676ad 100644 --- a/.github/workflows/all_core_tests.yml +++ b/.github/workflows/all_core_tests.yml @@ -19,10 +19,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/ready_doctest.yml b/.github/workflows/ready_doctest.yml index a5fc4dda..73519dde 100644 --- a/.github/workflows/ready_doctest.yml +++ b/.github/workflows/ready_doctest.yml @@ -22,10 +22,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/ready_linting.yml b/.github/workflows/ready_linting.yml index 0e1cb685..427d6847 100644 --- a/.github/workflows/ready_linting.yml +++ b/.github/workflows/ready_linting.yml @@ -22,10 +22,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' @@ -50,10 +52,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/ready_test_matrix.yml b/.github/workflows/ready_test_matrix.yml index be3136be..dda2f278 100644 --- a/.github/workflows/ready_test_matrix.yml +++ b/.github/workflows/ready_test_matrix.yml @@ -29,10 +29,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: ${{ matrix.py }} cache: 'pip' diff --git a/.github/workflows/ready_test_nonloc.yml b/.github/workflows/ready_test_nonloc.yml index 9a7d0d7b..e434d728 100644 --- a/.github/workflows/ready_test_nonloc.yml +++ b/.github/workflows/ready_test_nonloc.yml @@ -25,10 +25,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/release_check_sdist.yml b/.github/workflows/release_check_sdist.yml index bc2ac334..35e2505d 100644 --- a/.github/workflows/release_check_sdist.yml +++ b/.github/workflows/release_check_sdist.yml @@ -21,10 +21,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/release_doc_warnings.yml b/.github/workflows/release_doc_warnings.yml index 2cb09b18..f3e33c09 100644 --- a/.github/workflows/release_doc_warnings.yml +++ b/.github/workflows/release_doc_warnings.yml @@ -21,10 +21,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/release_enusre_no_ver_markers.yml b/.github/workflows/release_enusre_no_ver_markers.yml index 446bd552..da49997e 100644 --- a/.github/workflows/release_enusre_no_ver_markers.yml +++ b/.github/workflows/release_enusre_no_ver_markers.yml @@ -21,7 +21,9 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v6 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Error if any markers found run: | diff --git a/.github/workflows/release_flake8_noqa_nofail.yml b/.github/workflows/release_flake8_noqa_nofail.yml index 249ed3bb..16d9993d 100644 --- a/.github/workflows/release_flake8_noqa_nofail.yml +++ b/.github/workflows/release_flake8_noqa_nofail.yml @@ -21,10 +21,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/release_readme_doctest.yml b/.github/workflows/release_readme_doctest.yml index 9327fce3..4a690a07 100644 --- a/.github/workflows/release_readme_doctest.yml +++ b/.github/workflows/release_readme_doctest.yml @@ -21,10 +21,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' diff --git a/.github/workflows/release_test_file_coverage.yml b/.github/workflows/release_test_file_coverage.yml index d3bd5452..f2c40258 100644 --- a/.github/workflows/release_test_file_coverage.yml +++ b/.github/workflows/release_test_file_coverage.yml @@ -21,10 +21,12 @@ jobs: steps: - name: Check out repo - uses: actions/checkout@v4 + uses: actions/checkout@0c366fd6a839edf440554fa01a7085ccba70ac98 + with: + persist-credentials: false - name: Install Python - uses: actions/setup-python@v5 + uses: actions/setup-python@28f2168f4d98ee0445e3c6321f6e6616c83dd5ec with: python-version: '3.13' cache: 'pip' @@ -33,7 +35,7 @@ jobs: requirements-flake8.txt - name: Install CI requirements - run: pip install -r requirements-ci.txt -r requirements-flake8.txt + run: pip install -r requirements-ci.txt - name: Build docs & ensure scratch run: | @@ -42,7 +44,7 @@ jobs: mkdir scratch - name: Run pytest covering entire project tree - run: pytest --cov=. --nonloc --flake8_ext + run: pytest --cov=. --nonloc - name: Check 100% test code execution run: coverage report --include="tests/*" --fail-under=100 diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 7409274a..03c3c3f0 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -7,7 +7,7 @@ version: 2 # Build and VM configuration build: - os: 'ubuntu-22.04' + os: 'ubuntu-24.04' tools: python: '3.13' diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e793362..a90a49a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,7 @@ and this project follows an extension of fourth number represents an administrative maintenance release with no code changes. -### *Unreleased* +### [2.4] - 2026-03-23 #### Added @@ -21,6 +21,18 @@ changes. #### Tests + * Remove flake8_ext test file and machinery ([#336]). + * pytest environment now can easily de-sync from the flake8 environment + since flake8 is running in tox now. + * It was really always over-cautious, too. + + * Exclude `setup.py` from coverage ([#336]). + * Necessary due to a change in coverage.py behavior, maybe? + * Definitely is not expected to run during execution of the test suite. + + * Remove unused `ensure_doc_scratch` fixture from `conftest.py` ([#336]). + * Obsolete now that the README shell examples aren't doctested. + * Add 3.13t and 3.14t to `tox` test matrix ([#333]). * Also add report of the current GIL status to the `tox` env output. @@ -55,6 +67,21 @@ changes. #### Internal + * Convert `build` call into a `tox` env and remove `build` from + `requirements-dev.txt` ([#336]). + + * Remove redundant packages from `requirements-dev.txt` and + `requirements-ci.txt` that are pulled in by the `-e .` line ([#336]). + + * Add `tests/resource/objects_pdfminer*` to `MANIFEST.in`, to make that + inventory available to the docs build in the sdist unpack-and-test workflow + job ([#336]). + * Otherwise the docs job emits a warning. Not fatal, but better to have a + clean build. + + * Pin Actions versions to SHAs and de-persist credentials ([#336]). + * Closes [#322]. + * Add Actions workflow to error on a non-draft release branch if any `#VER#` markers remain in docs source ([#331]). @@ -81,6 +108,9 @@ changes. #### Documentation + * Update Sphinx, attrs, Python, etc. content to freshen and to match the new + inventories in the test resources ([#336]). + * Dynamically retrieve the current values of `PrsConst.SUGGEST_CONFIRM_LENGTH` and `PrsConst.DEF_THRESH` to define their replaces in `conf.py` ([#331]). @@ -785,7 +815,9 @@ changes. [#315]: https://github.com/bskinn/sphobjinv/pull/315 [#316]: https://github.com/bskinn/sphobjinv/pull/316 [#320]: https://github.com/bskinn/sphobjinv/pull/320 +[#322]: https://github.com/bskinn/sphobjinv/issues/322 [#325]: https://github.com/bskinn/sphobjinv/pull/325 [#327]: https://github.com/bskinn/sphobjinv/pull/327 [#331]: https://github.com/bskinn/sphobjinv/pull/331 [#333]: https://github.com/bskinn/sphobjinv/pull/333 +[#336]: https://github.com/bskinn/sphobjinv/pull/336 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c51c3a5e..e73bd72a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -122,6 +122,10 @@ flag: $ pytest --nonloc ``` +Most of these nonlocal tests now use an ephemeral local web server instead of +reaching out to the web, and so should run even without network access and +should just run faster in general. + 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 @@ -141,15 +145,15 @@ project, it is **not** set up to be an everyday test runner. Instead, its purpose for testing is 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.10 -through 3.14 installed and on `PATH` as `python3.10`, `python3.11`, 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.: +through 3.14 installed and on `PATH` as `python3.10`, `python3.11`, etc., as +well as free-threaded versions for Python 3.13 onward as `python3.13t`, etc. The +test matrix can be accelerated by using `tox`'s parallel execution mode; e.g.: ```bash $ tox -rp2 ``` + ## Code Autoformatting The project is set up with a `tox` environment to blacken the codebase; run with: @@ -244,20 +248,17 @@ 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. +Github Actions workflows are set up for the project, and should run on any forks +of the repository. Note that the CI runs differently on draft versus non-draft +PRs: on draft PRs, the only workflow that runs runs tests on Windows and Linux +with one Python version; whereas on non-draft PRs, a complete test matrix of +platforms and Python versions is run, as well as doctests and linting checks. Github Actions runs the test suite on Linux for Python 3.10 through 3.14, as well as the `flake8` lints and the Sphinx doctests. By default, the Github Actions will run on all commits, but the workflows 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`. -The Azure Pipelines workflows now [also obey `[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 diff --git a/LICENSE.txt b/LICENSE.txt index e892de6b..8afcbd75 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2016-2025 Brian Skinn and community contributors +Copyright (c) 2016-2026 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 diff --git a/MANIFEST.in b/MANIFEST.in index 0acd4658..51cd741a 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -8,7 +8,7 @@ include doc/make.bat doc/Makefile graft tests prune tests/resource -include tests/resource/objects_attrs* tests/resource/objects_sarge* +include tests/resource/objects_attrs* tests/resource/objects_sarge* tests/resource/objects_pdfminer* global-exclude __pycache__/* prune **/*.egg-info diff --git a/README.md b/README.md index 8aef5f0b..6a3e8858 100644 --- a/README.md +++ b/README.md @@ -42,26 +42,24 @@ For internal cross-references, locate `objects.inv` within `build/html`: ```none $ sphobjinv suggest doc/build/html/objects.inv as_rst -st 58 ------------------------------------------------- +----------------------------------------------------------------------------------------------------------- Cannot infer intersphinx_mapping from a local objects.inv. ------------------------------------------------- +----------------------------------------------------------------------------------------------------------- Project: sphobjinv -Version: 2.3 +Version: 2.4 -220 objects in inventory. +151 objects in inventory. ------------------------------------------------- - -11 results found at/above current threshold of 58. +----------------------------------------------------------------------------------------------------------- +10 results found at/above current threshold of 58. Name Score --------------------------------------------------- ------- :py:property:`sphobjinv.data.SuperDataObj.as_rst` 60 -:py:class:`sphobjinv.cli.parser.PrsConst` 59 :py:class:`sphobjinv.data.DataFields` 59 :py:class:`sphobjinv.data.DataObjBytes` 59 :py:class:`sphobjinv.data.DataObjStr` 59 @@ -84,31 +82,31 @@ cross-reference the `linspace` function from numpy (see [here][numpy linspace]): ```none -$ sphobjinv suggest https://numpy.org/doc/1.26/reference/index.html linspace -su +$ sphobjinv suggest https://numpy.org/doc/2.4/reference/index.html linspace -su -Attempting https://numpy.org/doc/1.26/reference/index.html ... +Attempting https://numpy.org/doc/2.4/reference/index.html ... ... no recognized inventory. -Attempting "https://numpy.org/doc/1.26/reference/index.html/objects.inv" ... +Attempting "https://numpy.org/doc/2.4/reference/index.html/objects.inv" ... ... HTTP error: 404 Not Found. -Attempting "https://numpy.org/doc/1.26/reference/objects.inv" ... +Attempting "https://numpy.org/doc/2.4/reference/objects.inv" ... ... HTTP error: 404 Not Found. -Attempting "https://numpy.org/doc/1.26/objects.inv" ... +Attempting "https://numpy.org/doc/2.4/objects.inv" ... ... inventory found. ----------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------- The intersphinx_mapping for this docset is LIKELY: - (https://numpy.org/doc/1.26/, None) + (https://numpy.org/doc/2.4/, None) ----------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------- Project: NumPy -Version: 1.26 +Version: 2.4 -8152 objects in inventory. +8456 objects in inventory. ----------------------------------------------------------------------------------- +----------------------------------------------------------------------------------------------------------- 8 results found at/above current threshold of 75. @@ -154,13 +152,13 @@ inventory creation/modification: >>> import sphobjinv as soi >>> inv = soi.Inventory('doc/build/html/objects.inv') >>> print(inv) - + >>> inv.project 'sphobjinv' >>> inv.version -'2.3' +'2.4' >>> inv.objects[0] -DataObjStr(name='sphobjinv.cli.convert', domain='py', role='module', priority='0', uri='cli/implementation/convert.html#module-$', dispname='-') +DataObjStr(name='sphobjinv.data', domain='py', role='module', priority='0', uri='api/data.html#module-$', dispname='-') ``` @@ -177,7 +175,7 @@ Available on [PyPI][pypi link target] (`pip install sphobjinv`). Source on [GitHub][github repo]. Bug reports and feature requests are welcomed at the [Issues][github issue tracker] page there. -Copyright (c) Brian Skinn 2016-2025 +Copyright (c) 2016-2026 Brian Skinn and community contributors The `sphobjinv` documentation (including docstrings and README) is licensed under a [Creative Commons Attribution 4.0 International License][cc-by 4.0] @@ -198,7 +196,7 @@ under a [Creative Commons Attribution 4.0 International License][cc-by 4.0] [mit license]: https://opensource.org/licenses/MIT [numpy linspace]: https://numpy.org/doc/1.26/reference/generated/numpy.linspace.html [pepy badge]: https://pepy.tech/badge/sphobjinv/month -[pepy link target]: https://pepy.tech/projects/sphobjinv?timeRange=threeMonths&category=version&includeCIDownloads=true&granularity=daily&viewType=chart&versions=2.0.*%2C2.1.*%2C2.2.*%2C2.3.* +[pepy link target]: https://pepy.tech/projects/sphobjinv?timeRange=threeMonths&category=version&includeCIDownloads=true&granularity=daily&versions=2.3.*%2C2.4* [pypi badge]: https://img.shields.io/pypi/v/sphobjinv.svg?logo=pypi] [pypi link target]: https://pypi.org/project/sphobjinv [python versions badge]: https://img.shields.io/pypi/pyversions/sphobjinv.svg?logo=python diff --git a/doc/source/_static/mouseover_example.png b/doc/source/_static/mouseover_example.png index eef34b44..7e604774 100644 Binary files a/doc/source/_static/mouseover_example.png and b/doc/source/_static/mouseover_example.png differ diff --git a/doc/source/api_usage.rst b/doc/source/api_usage.rst index 8e6e097c..b8f236a5 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 - '22.1' + '25.4' >>> inv.count - 129 + 180 The location of the inventory file to import can also be provided as a :class:`pathlib.Path`, instead of as a string: @@ -38,16 +38,16 @@ a |list| in the :attr:`~sphobjinv.inventory.Inventory.objects` attribute: .. doctest:: api_inspect >>> len(inv.objects) - 129 + 180 >>> dobj = inv.objects[0] >>> dobj - DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='api-attr.html#module-$', dispname='-') >>> dobj.name 'attr' >>> dobj.domain 'py' - >>> [d.name for d in inv.objects if 'validator' in d.uri] - ['api_validators', 'examples_validators'] + >>> [d.name for d in inv.objects if 'validator' in d.name][:2] + ['attr.get_run_validators', 'attr.set_run_validators'] :class:`~sphobjinv.inventory.Inventory` objects can also import from plaintext or zlib-compressed inventories, as |bytes|: @@ -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,7 +118,7 @@ The :class:`~sphobjinv.data.DataObjStr` instances can be edited in place: >>> inv = soi.Inventory('objects_attrs.inv') >>> inv.objects[0] - DataObjStr(name='attr', domain='py', role='module', priority='0', uri='index.html#module-$', dispname='-') + DataObjStr(name='attr', domain='py', role='module', priority='0', uri='api-attr.html#module-$', dispname='-') >>> inv.objects[0].uri = 'attribute.html' >>> inv.objects[0] DataObjStr(name='attr', domain='py', role='module', priority='0', uri='attribute.html', dispname='-') @@ -130,7 +130,7 @@ 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 - 130 + 181 >>> inv.objects[-1] DataObjStr(name='attr.Generator', domain='py', role='module', priority='0', uri='generator.html', dispname='-') @@ -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: 22.1' + b'# Version: 25.4' b'# The remainder of this file is compressed using zlib.' - b'attr py:module 0 index.html#module-$ -' - b'attr.VersionInfo py:class 1 api.html#$ -' + b'attr py:module 0 api-attr.html#module-$ -' + b'attr.Attribute py:class 1 api-attr.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 py:module 0 index.html#module-attr attr' - b'attr.VersionInfo py:class 1 api.html#attr.VersionInfo attr.VersionInfo' + b'attr py:module 0 api-attr.html#module-attr attr' + b'attr.Attribute py:class 1 api-attr.html#attr.Attribute attr.Attribute' >>> do = inv.objects[0] >>> do.data_line(expand=True) - 'attr py:module 0 index.html#module-attr attr' + 'attr py:module 0 api-attr.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: 22.1 + # Version: 25.4 # The remainder of this file is compressed using zlib. - attr py:module 0 index.html#module-$ - - attr.VersionInfo py:class 1 api.html#$ - + attr py:module 0 api-attr.html#module-$ - + attr.Attribute py:class 1 api-attr.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: 22.1' + b'# Version: 25.4' b'# The remainder of this file is compressed using zlib.' >>> print(Path('objects_attrs_new.inv').read_bytes().splitlines()[6][:10]) - b'\xbf\x86\x8fL49\xc4\x91\xb8\x8c' + b"$e2'\x92\xbde\xaa\xbdj" For JSON: diff --git a/doc/source/cli/convert.rst b/doc/source/cli/convert.rst index f3871938..7220276c 100644 --- a/doc/source/cli/convert.rst +++ b/doc/source/cli/convert.rst @@ -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: 22.1 + # Version: 25.4 # The remainder of this file is compressed using zlib. - attr py:module 0 index.html#module-$ - - attr.VersionInfo py:class 1 api.html#$ - + attr py:module 0 api-attr.html#module-$ - + attr.Attribute py:class 1 api-attr.html#$ - A different target filename can be specified, to avoid overwriting an existing file: @@ -76,7 +76,7 @@ indicated URL): >>> print(file_head('objects.txt', head=6)) # Sphinx inventory version 2 # Project: attrs - # Version: 22.1 + # Version: ... # The remainder of this file is compressed using zlib. attr py:module 0 index.html#module-$ - attr.VersionInfo py:class 1 api.html#$ - @@ -135,11 +135,12 @@ 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: 22.1 + # Version: 25.4 # The remainder of this file is compressed using zlib. - 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 py:module 0 api-attr.html#module-$ - + attr.Attribute py:class 1 api-attr.html#$ - + attr.NOTHING py:data 1 api-attr.html#$ - + attr.VersionInfo py:class 1 api-attr.html#$ - ... diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst index 2d26cc07..952f11d7 100644 --- a/doc/source/cli/index.rst +++ b/doc/source/cli/index.rst @@ -12,7 +12,7 @@ The primary CLI for |soi| is implemented using two subcommands of the - ``sphobjinv suggest`` (:doc:`docs page `), which provides suggestions for objects in an inventory matching a desired search term. -As of v##VER##, |soi| also provides an auxiliary entrypoint, +As of v2.4, |soi| also provides an auxiliary entrypoint, ``sphobjinv-textconv`` (:doc:`docs page `), which takes one required argument: a path to a file on disk. This entrypoint attempts to instantiate an |Inventory| with this file and emit its plaintext contents to |stdout| with no diff --git a/doc/source/cli/textconv.rst b/doc/source/cli/textconv.rst index fd13a371..b01c7b95 100644 --- a/doc/source/cli/textconv.rst +++ b/doc/source/cli/textconv.rst @@ -38,7 +38,7 @@ Ultimately, a textconv requires three things: *.inv diff=objects_inv With |sphobjinv-textconv| configured in this fashion as a textconv for Sphinx -inventory files, the following should all yield _nearly_ the same output. +inventory files, the following should all yield *nearly* the same output. Using ``sphobjinv convert``: @@ -82,4 +82,4 @@ will render correctly in ReadTheDocs builds): Display brief package version information and exit. -.. versionadded:: ##VER## +.. versionadded:: 2.4 diff --git a/doc/source/conf.py b/doc/source/conf.py index 5abed10c..c9a29321 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -21,7 +21,7 @@ # -- Project information ----------------------------------------------------- project = "sphobjinv" -copyright = "2016-2025, Brian Skinn" +copyright = "2016-2026, Brian Skinn and community contributors" author = "Brian Skinn" # The full version for `release`, including alpha/beta/rc tags diff --git a/doc/source/customfile.rst b/doc/source/customfile.rst index f37b8cae..2cbc3587 100644 --- a/doc/source/customfile.rst +++ b/doc/source/customfile.rst @@ -143,7 +143,7 @@ can be found at the GitHub repo intersphinx_mapping = { # Standard reference to web docs, with web objects.inv - 'python': ('https://docs.python.org/3.13', None), + 'python': ('https://docs.python.org/3.14', None), # 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/'), diff --git a/doc/source/index.rst b/doc/source/index.rst index d07d5be4..28f3a74e 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 @@ -57,6 +57,8 @@ and package managers, including: * Arch Linux: ``python-sphobjinv`` + * Debian: ``python-sphobjinv`` (`info `__) + * Fedora: ``python-sphobjinv`` (`info `__) * Gentoo: ``dev-python/sphobjinv`` (`info `__) diff --git a/doc/source/syntax.rst b/doc/source/syntax.rst index ab51b116..0b0f57ed 100644 --- a/doc/source/syntax.rst +++ b/doc/source/syntax.rst @@ -5,8 +5,8 @@ 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 May 2024 -(Sphinx v7.3.7). It is based on inspection of |objects.inv| files "in the +Sphinx documentation. The below syntax is believed to be accurate as of March 2026 +(Sphinx v9.1.0). 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 @@ -27,7 +27,7 @@ data line. ---- **The first line** `must be exactly -`__: +`__: .. code-block:: none @@ -36,7 +36,7 @@ data line. ---- **The second and third lines** `must obey -`__ +`__ the template: .. code-block:: none @@ -56,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 @@ -67,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 @@ -132,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; values of ``0`` (higher priority) or ``2`` (lower priority) may also occur. @@ -194,7 +194,7 @@ of cross-references from other documentation source. **For illustration**, the following is the entry for the :meth:`join() ` method of the :class:`str` class in the -Python 3.12 |objects.inv|, broken out field-by-field: +Python 3.14 |objects.inv|, broken out field-by-field: .. code-block:: none @@ -217,11 +217,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: @@ -271,11 +271,11 @@ as in :obj:`This is join! `: .. |prio_js_search| replace:: here -.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/ac3f74a3e0fbb326f73989a16dfa369e072064ca/sphinx/themes/basic/static/searchtools.js#L28-L46 +.. _prio_js_search: https://github.com/sphinx-doc/sphinx/blob/e552f8429c3039bc0649a7da82bdfa0df3273c3d/sphinx/themes/basic/static/searchtools.js#L21-L39 .. |prio_py_search| replace:: here -.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/ac3f74a3e0fbb326f73989a16dfa369e072064ca/sphinx/search/__init__.py#L344-L345 +.. _prio_py_search: https://github.com/sphinx-doc/sphinx/blob/e552f8429c3039bc0649a7da82bdfa0df3273c3d/sphinx/search/__init__.py#L377-L378 .. |sphinx_uri_issue| replace:: sphinx-doc/sphinx#7096 @@ -297,4 +297,4 @@ as in :obj:`This is join! `: .. _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/ac3f74a3e0fbb326f73989a16dfa369e072064ca/sphinx/util/inventory.py#L134-L135 +.. _parsing regex: https://github.com/sphinx-doc/sphinx/blob/e552f8429c3039bc0649a7da82bdfa0df3273c3d/sphinx/util/inventory.py#L115-L119 diff --git a/pyproject.toml b/pyproject.toml index 0ad2588e..1ed6313f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,11 +8,10 @@ requires = [ [project] name = "sphobjinv" description = "Sphinx objects.inv Inspection/Manipulation Tool" -license = {text = "MIT License"} +license = "MIT" +license-files = ["LICENSE.txt"] authors = [{name = "Brian Skinn", email = "brian.skinn@gmail.com"}] classifiers = [ - "License :: OSI Approved", - "License :: OSI Approved :: MIT License", "Natural Language :: English", "Environment :: Console", "Framework :: Sphinx", @@ -38,7 +37,7 @@ requires-python = ">=3.10" dependencies = [ "attrs>=19.2", "certifi", - "jsonschema>=3.0", + "jsonschema>=3.1.1", ] dynamic = ["version", "readme"] @@ -57,7 +56,6 @@ sphobjinv-textconv = "sphobjinv.cli.core:main_textconv" [tool.setuptools] package-dir = {"" = "src"} platforms = ["any"] -license-files = ["LICENSE.txt"] include-package-data = false [tool.setuptools.packages.find] @@ -68,6 +66,7 @@ namespaces = false version = {attr = "sphobjinv.version.__version__"} [tool.black] +target-version = ["py313"] line-length = 88 include = ''' ( diff --git a/requirements-ci.txt b/requirements-ci.txt index 33429641..68da2580 100644 --- a/requirements-ci.txt +++ b/requirements-ci.txt @@ -1,8 +1,5 @@ -attrs>=19.2 -certifi coverage dictdiffer -jsonschema md-toc pytest>=4.4.0 pytest-check>=1.1.2 diff --git a/requirements-dev.txt b/requirements-dev.txt index 5070a9a5..df2e9b95 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,9 +1,5 @@ -attrs>=19.2 -build -certifi coverage dictdiffer -jsonschema md-toc pytest>=4.4.0 pytest-check>=1.1.2 diff --git a/setup.py b/setup.py index f172d296..00615320 100644 --- a/setup.py +++ b/setup.py @@ -9,13 +9,13 @@ exec(Path("src", "sphobjinv", "version.py").read_text(encoding="utf-8"), exec_ns) __version__ = exec_ns["__version__"] -version_override = "2.3.1.2" +version_override = None def readme(): content = Path("README.md").read_text(encoding="utf-8") - new_ver = version_override if version_override else __version__ + new_ver = version_override or __version__ # Helper function def content_update(content, pattern, sub): diff --git a/src/sphobjinv/__init__.py b/src/sphobjinv/__init__.py index 0e141f96..e46dd28a 100644 --- a/src/sphobjinv/__init__.py +++ b/src/sphobjinv/__init__.py @@ -10,7 +10,7 @@ 17 May 2016 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/__main__.py b/src/sphobjinv/__main__.py index 6e307758..d063bb24 100644 --- a/src/sphobjinv/__main__.py +++ b/src/sphobjinv/__main__.py @@ -10,7 +10,7 @@ 15 May 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/_vendored/__init__.py b/src/sphobjinv/_vendored/__init__.py index 36ba0197..b5f7e176 100644 --- a/src/sphobjinv/_vendored/__init__.py +++ b/src/sphobjinv/_vendored/__init__.py @@ -12,7 +12,7 @@ 11 Dec 2021 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py index ff3129d3..f88ee546 100644 --- a/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py +++ b/src/sphobjinv/_vendored/fuzzywuzzy/__init__.py @@ -25,7 +25,7 @@ 11 Dec 2021 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/__init__.py b/src/sphobjinv/cli/__init__.py index 357e6e8c..d7b267b8 100644 --- a/src/sphobjinv/cli/__init__.py +++ b/src/sphobjinv/cli/__init__.py @@ -10,7 +10,7 @@ 15 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/convert.py b/src/sphobjinv/cli/convert.py index 1a342d63..829f1c79 100644 --- a/src/sphobjinv/cli/convert.py +++ b/src/sphobjinv/cli/convert.py @@ -10,7 +10,7 @@ 20 Oct 2022 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/core.py b/src/sphobjinv/cli/core.py index 9130f992..3fbc6d1c 100644 --- a/src/sphobjinv/cli/core.py +++ b/src/sphobjinv/cli/core.py @@ -10,7 +10,7 @@ 15 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/load.py b/src/sphobjinv/cli/load.py index 32405758..07032c95 100644 --- a/src/sphobjinv/cli/load.py +++ b/src/sphobjinv/cli/load.py @@ -10,7 +10,7 @@ 17 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/parser.py b/src/sphobjinv/cli/parser.py index 19727e18..44e1a1ab 100644 --- a/src/sphobjinv/cli/parser.py +++ b/src/sphobjinv/cli/parser.py @@ -10,7 +10,7 @@ 15 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -44,7 +44,8 @@ class PrsConst: #: Version &c. output blurb VER_TXT = ( - f"\nsphobjinv v{__version__}\n\nCopyright (c) Brian Skinn 2016-2025\n" + f"\nsphobjinv v{__version__}\n\n" + "Copyright (c) 2016-2026 Brian Skinn and community contributors\n" "License: The MIT License\n\n" "Bug reports & feature requests:" " https://github.com/bskinn/sphobjinv\n" diff --git a/src/sphobjinv/cli/paths.py b/src/sphobjinv/cli/paths.py index de9bfc23..1ce9581e 100644 --- a/src/sphobjinv/cli/paths.py +++ b/src/sphobjinv/cli/paths.py @@ -10,7 +10,7 @@ 19 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/suggest.py b/src/sphobjinv/cli/suggest.py index 1fb7dd56..865dd4a6 100644 --- a/src/sphobjinv/cli/suggest.py +++ b/src/sphobjinv/cli/suggest.py @@ -10,7 +10,7 @@ 20 Oct 2022 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/ui.py b/src/sphobjinv/cli/ui.py index 2ab2290b..a886880b 100644 --- a/src/sphobjinv/cli/ui.py +++ b/src/sphobjinv/cli/ui.py @@ -10,7 +10,7 @@ 19 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/cli/write.py b/src/sphobjinv/cli/write.py index f7f0816e..b9a9930d 100644 --- a/src/sphobjinv/cli/write.py +++ b/src/sphobjinv/cli/write.py @@ -10,7 +10,7 @@ 19 Nov 2020 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/data.py b/src/sphobjinv/data.py index 10a6c7d7..76cade55 100644 --- a/src/sphobjinv/data.py +++ b/src/sphobjinv/data.py @@ -10,7 +10,7 @@ 7 Nov 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/enum.py b/src/sphobjinv/enum.py index d046dc95..3fa4fcd0 100644 --- a/src/sphobjinv/enum.py +++ b/src/sphobjinv/enum.py @@ -10,7 +10,7 @@ 4 May 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/error.py b/src/sphobjinv/error.py index 37422303..ba07b200 100644 --- a/src/sphobjinv/error.py +++ b/src/sphobjinv/error.py @@ -10,7 +10,7 @@ 5 Nov 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/fileops.py b/src/sphobjinv/fileops.py index feba9dad..e30c4b42 100644 --- a/src/sphobjinv/fileops.py +++ b/src/sphobjinv/fileops.py @@ -10,7 +10,7 @@ 5 Nov 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/inventory.py b/src/sphobjinv/inventory.py index 33c685e5..d56c7124 100644 --- a/src/sphobjinv/inventory.py +++ b/src/sphobjinv/inventory.py @@ -10,7 +10,7 @@ 7 Dec 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/re.py b/src/sphobjinv/re.py index dfe4c9e6..e42ab29d 100644 --- a/src/sphobjinv/re.py +++ b/src/sphobjinv/re.py @@ -10,7 +10,7 @@ 5 Nov 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -45,9 +45,7 @@ [#][ ]Project:[ ] # Preamble (?P<{HF.Project.value}>.*?) # Lazy rest of line is project name \r?$ # Ignore possible CR at EOL - """.encode( - encoding="utf-8" - ), + """.encode(encoding="utf-8"), re.M | re.X, ) @@ -58,9 +56,7 @@ [#][ ]Version:[ ] # Preamble (?P<{HF.Version.value}>.*?) # Lazy rest of line is version \r?$ # Ignore possible CR at EOL - """.encode( - encoding="utf-8" - ), + """.encode(encoding="utf-8"), re.M | re.X, ) diff --git a/src/sphobjinv/schema.py b/src/sphobjinv/schema.py index b609b042..2cc54d2b 100644 --- a/src/sphobjinv/schema.py +++ b/src/sphobjinv/schema.py @@ -11,7 +11,7 @@ 7 Dec 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/src/sphobjinv/version.py b/src/sphobjinv/version.py index 3840d8c1..b961ad10 100644 --- a/src/sphobjinv/version.py +++ b/src/sphobjinv/version.py @@ -10,7 +10,7 @@ 18 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -29,4 +29,4 @@ """ -__version__ = "2.3.2.dev0" +__version__ = "2.4.1.dev0" diff --git a/src/sphobjinv/zlib.py b/src/sphobjinv/zlib.py index 649d54c6..34dfe6af 100644 --- a/src/sphobjinv/zlib.py +++ b/src/sphobjinv/zlib.py @@ -10,7 +10,7 @@ 5 Nov 2017 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/conftest.py b/tests/conftest.py index 19db6815..ffd9fdf4 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -61,9 +61,6 @@ def pytest_addoption(parser): ), ) parser.addoption("--nonloc", action="store_true", help="Include nonlocal tests") - parser.addoption( - "--flake8_ext", action="store_true", help="Include flake8 extensions test" - ) @pytest.fixture(scope="session") @@ -158,21 +155,13 @@ def scratch_path(tmp_path, res_path, misc_info, is_win, unix2dos): # With the conversion of resources/objects_attrs.txt to Unix EOLs in order to # provide for a Unix-testable sdist, on Windows systems this resource needs # to be converted to DOS EOLs for consistency. - if is_win: + if is_win: # pragma: no cover win_path = tmp_path / f"{scr_base}{misc_info.Extensions.DEC.value}" win_path.write_bytes(unix2dos(win_path.read_bytes())) yield tmp_path -@pytest.fixture(scope="session") -def ensure_doc_scratch(): - """Ensure doc/scratch dir exists, for README shell examples.""" - (Path(__file__).resolve().parent.parent / "doc" / "scratch").mkdir( - parents=True, exist_ok=True - ) - - @pytest.fixture(scope="session") def bytes_txt(misc_info, res_path): """Load and return the contents of the example objects_attrs.txt as bytes.""" @@ -220,7 +209,7 @@ def func(path): """Perform the 'live' inventory load test.""" try: sphinx_ifile_load(path) - except Exception as e: # noqa: PIE786 + except Exception as e: # noqa: PIE786 pragma: no cover # An exception here is a failing test, not a test error. pytest.fail(e) @@ -265,7 +254,7 @@ def func(arglist, *, command=CLICommand.Core, expect=0): # , suffix=None): except SystemExit as e: retcode = e.args[0] ok = True - else: + else: # pragma: no cover ok = False # Do all pytesty stuff outside monkeypatch context @@ -287,7 +276,7 @@ def func(path): res_bytes = Path(misc_info.res_decomp_path).read_bytes() tgt_bytes = Path(path).read_bytes() # .replace(b"\r\n", b"\n") - if is_win: + if is_win: # pragma: no cover # Have to explicitly convert these newlines, now that the # tests/resource/objects_attrs.txt file is marked 'binary' in # .gitattributes @@ -310,8 +299,8 @@ def func(inv, source_type): """ assert inv.project == "attrs" - assert inv.version == "22.1" - assert inv.count == 129 + assert inv.version == "25.4" + assert inv.count == 180 assert inv.source_type return func diff --git a/tests/enum.py b/tests/enum.py index 685d2406..0c1b9757 100644 --- a/tests/enum.py +++ b/tests/enum.py @@ -10,7 +10,7 @@ 22 Dec 2025 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/fixtures_http.py b/tests/fixtures_http.py index 27abe554..7627db42 100644 --- a/tests/fixtures_http.py +++ b/tests/fixtures_http.py @@ -10,7 +10,7 @@ 24 Dec 2025 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -94,7 +94,7 @@ def resource_http_base_url() -> Generator[str, None, None]: """Provide base URL of HTTP server exposing tests/resource/*.""" # noqa: RST213 resource_dir = Path(__file__).resolve().parent / "resource" - if not resource_dir.is_dir(): + if not resource_dir.is_dir(): # pragma: no cover raise RuntimeError( f"Expected test resource directory not found: {resource_dir}" ) @@ -119,7 +119,7 @@ def resource_url(resource_http_base_url: str) -> Callable[[str], str]: def _calc_path(rel_path: str) -> str: """Calculate the full test-resource URL from a relative URL.""" # Prevent escaping the resource directory. - if ".." in Path(rel_path).parts: + if ".." in Path(rel_path).parts: # pragma: no cover raise ValueError("Path must not contain '..'") # Ensure consistent URL path separators. diff --git a/tests/resource/objects_attrs.inv b/tests/resource/objects_attrs.inv index 85189bdf..7c5a9b0a 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 b1144317..d0ad36c1 100644 --- a/tests/resource/objects_attrs.json +++ b/tests/resource/objects_attrs.json @@ -1 +1 @@ -{"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 +{"project": "attrs", "version": "25.4", "count": 180, "0": {"name": "attr", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "1": {"name": "attr.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "2": {"name": "attr.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "3": {"name": "attr.VersionInfo", "domain": "py", "role": "class", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "4": {"name": "attr._make.Attribute", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Attribute", "dispname": "-"}, "5": {"name": "attr._make.ClassProps", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.ClassProps", "dispname": "-"}, "6": {"name": "attr._make.ClassProps.Hashability", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.ClassProps.Hashability", "dispname": "-"}, "7": {"name": "attr._make.ClassProps.KeywordOnly", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.ClassProps.KeywordOnly", "dispname": "-"}, "8": {"name": "attr._make.Converter", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Converter", "dispname": "-"}, "9": {"name": "attr._make.Factory", "domain": "py", "role": "class", "priority": "-1", "uri": "api.html#attrs.Factory", "dispname": "-"}, "10": {"name": "attr._version_info.VersionInfo", "domain": "py", "role": "class", "priority": "-1", "uri": "api-attr.html#attr.VersionInfo", "dispname": "-"}, "11": {"name": "attr.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "12": {"name": "attr.assoc", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "13": {"name": "attr.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "14": {"name": "attr.attrs", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "15": {"name": "attr.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "16": {"name": "attr.converters", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "17": {"name": "attr.define", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "18": {"name": "attr.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "19": {"name": "attr.exceptions", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "20": {"name": "attr.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.AttrsAttributeNotFoundError", "dispname": "-"}, "21": {"name": "attr.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.DefaultAlreadySetError", "dispname": "-"}, "22": {"name": "attr.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenAttributeError", "dispname": "-"}, "23": {"name": "attr.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenError", "dispname": "-"}, "24": {"name": "attr.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.FrozenInstanceError", "dispname": "-"}, "25": {"name": "attr.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotAnAttrsClassError", "dispname": "-"}, "26": {"name": "attr.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.NotCallableError", "dispname": "-"}, "27": {"name": "attr.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.PythonTooOldError", "dispname": "-"}, "28": {"name": "attr.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "-1", "uri": "api.html#attrs.exceptions.UnannotatedAttributeError", "dispname": "-"}, "29": {"name": "attr.field", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "30": {"name": "attr.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "31": {"name": "attr.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "32": {"name": "attr.filters", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "33": {"name": "attr.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "34": {"name": "attr.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "35": {"name": "attr.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "36": {"name": "attr.get_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "37": {"name": "attr.has", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "38": {"name": "attr.ib", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "39": {"name": "attr.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "40": {"name": "attr.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "41": {"name": "attr.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "42": {"name": "attr.s", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "43": {"name": "attr.set_run_validators", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "44": {"name": "attr.setters", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "45": {"name": "attr.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api-attr.html#$", "dispname": "-"}, "46": {"name": "attr.validators", "domain": "py", "role": "module", "priority": "0", "uri": "api-attr.html#module-$", "dispname": "-"}, "47": {"name": "attrs", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "48": {"name": "attrs.Attribute", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "49": {"name": "attrs.Attribute.evolve", "domain": "py", "role": "method", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "50": {"name": "attrs.ClassProps", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "51": {"name": "attrs.ClassProps.Hashability", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "52": {"name": "attrs.ClassProps.Hashability.HASHABLE", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "53": {"name": "attrs.ClassProps.Hashability.HASHABLE_CACHED", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "54": {"name": "attrs.ClassProps.Hashability.LEAVE_ALONE", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "55": {"name": "attrs.ClassProps.Hashability.UNHASHABLE", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "56": {"name": "attrs.ClassProps.KeywordOnly", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "57": {"name": "attrs.ClassProps.KeywordOnly.FORCE", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "58": {"name": "attrs.ClassProps.KeywordOnly.NO", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "59": {"name": "attrs.ClassProps.KeywordOnly.YES", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "60": {"name": "attrs.ClassProps.added_eq", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "61": {"name": "attrs.ClassProps.added_init", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "62": {"name": "attrs.ClassProps.added_match_args", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "63": {"name": "attrs.ClassProps.added_ordering", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "64": {"name": "attrs.ClassProps.added_pickling", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "65": {"name": "attrs.ClassProps.added_repr", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "66": {"name": "attrs.ClassProps.added_str", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "67": {"name": "attrs.ClassProps.collected_fields_by_mro", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "68": {"name": "attrs.ClassProps.field_transformer", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "69": {"name": "attrs.ClassProps.has_weakref_slot", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "70": {"name": "attrs.ClassProps.hashability", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "71": {"name": "attrs.ClassProps.is_exception", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "72": {"name": "attrs.ClassProps.is_frozen", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "73": {"name": "attrs.ClassProps.is_slotted", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "74": {"name": "attrs.ClassProps.kw_only", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "75": {"name": "attrs.ClassProps.on_setattr_hook", "domain": "py", "role": "attribute", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "76": {"name": "attrs.Converter", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "77": {"name": "attrs.Factory", "domain": "py", "role": "class", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "78": {"name": "attrs.NOTHING", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "79": {"name": "attrs.asdict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "80": {"name": "attrs.astuple", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "81": {"name": "attrs.cmp_using", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "82": {"name": "attrs.converters", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "83": {"name": "attrs.converters.default_if_none", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "84": {"name": "attrs.converters.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "85": {"name": "attrs.converters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "86": {"name": "attrs.converters.to_bool", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "87": {"name": "attrs.define", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "88": {"name": "attrs.evolve", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "89": {"name": "attrs.exceptions", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "90": {"name": "attrs.exceptions.AttrsAttributeNotFoundError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "91": {"name": "attrs.exceptions.DefaultAlreadySetError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "92": {"name": "attrs.exceptions.FrozenAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "93": {"name": "attrs.exceptions.FrozenError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "94": {"name": "attrs.exceptions.FrozenInstanceError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "95": {"name": "attrs.exceptions.NotAnAttrsClassError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "96": {"name": "attrs.exceptions.NotCallableError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "97": {"name": "attrs.exceptions.PythonTooOldError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "98": {"name": "attrs.exceptions.UnannotatedAttributeError", "domain": "py", "role": "exception", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "99": {"name": "attrs.field", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "100": {"name": "attrs.fields", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "101": {"name": "attrs.fields_dict", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "102": {"name": "attrs.filters", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "103": {"name": "attrs.filters.exclude", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "104": {"name": "attrs.filters.include", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "105": {"name": "attrs.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "106": {"name": "attrs.has", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "107": {"name": "attrs.inspect", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "108": {"name": "attrs.make_class", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "109": {"name": "attrs.mutable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "110": {"name": "attrs.resolve_types", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "111": {"name": "attrs.setters", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "112": {"name": "attrs.setters.NO_OP", "domain": "py", "role": "data", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "113": {"name": "attrs.setters.convert", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "114": {"name": "attrs.setters.frozen", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "115": {"name": "attrs.setters.pipe", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "116": {"name": "attrs.setters.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "117": {"name": "attrs.validate", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "118": {"name": "attrs.validators", "domain": "py", "role": "module", "priority": "0", "uri": "api.html#module-$", "dispname": "-"}, "119": {"name": "attrs.validators.and_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "120": {"name": "attrs.validators.deep_iterable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "121": {"name": "attrs.validators.deep_mapping", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "122": {"name": "attrs.validators.disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "123": {"name": "attrs.validators.ge", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "124": {"name": "attrs.validators.get_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "125": {"name": "attrs.validators.gt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "126": {"name": "attrs.validators.in_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "127": {"name": "attrs.validators.instance_of", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "128": {"name": "attrs.validators.is_callable", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "129": {"name": "attrs.validators.le", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "130": {"name": "attrs.validators.lt", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "131": {"name": "attrs.validators.matches_re", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "132": {"name": "attrs.validators.max_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "133": {"name": "attrs.validators.min_len", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "134": {"name": "attrs.validators.not_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "135": {"name": "attrs.validators.optional", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "136": {"name": "attrs.validators.or_", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "137": {"name": "attrs.validators.set_disabled", "domain": "py", "role": "function", "priority": "1", "uri": "api.html#$", "dispname": "-"}, "138": {"name": "api", "domain": "std", "role": "doc", "priority": "-1", "uri": "api.html", "dispname": "API Reference"}, "139": {"name": "api-attr", "domain": "std", "role": "doc", "priority": "-1", "uri": "api-attr.html", "dispname": "API Reference for the attr Namespace"}, "140": {"name": "api-validators", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Validators"}, "141": {"name": "api_setters", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#api-setters", "dispname": "Setters"}, "142": {"name": "asdict", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Converting to Collections Types"}, "143": {"name": "attribute", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-$", "dispname": "-"}, "144": {"name": "changelog", "domain": "std", "role": "doc", "priority": "-1", "uri": "changelog.html", "dispname": "Changelog"}, "145": {"name": "comparison", "domain": "std", "role": "doc", "priority": "-1", "uri": "comparison.html", "dispname": "Comparison"}, "146": {"name": "converters", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Converters"}, "147": {"name": "custom-comparison", "domain": "std", "role": "label", "priority": "-1", "uri": "comparison.html#$", "dispname": "Customization"}, "148": {"name": "defaults", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Defaults"}, "149": {"name": "dict classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dict-classes", "dispname": "-"}, "150": {"name": "dunder methods", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-dunder-methods", "dispname": "-"}, "151": {"name": "examples", "domain": "std", "role": "doc", "priority": "-1", "uri": "examples.html", "dispname": "attrs by Example"}, "152": {"name": "examples-validators", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Validators"}, "153": {"name": "extending", "domain": "std", "role": "doc", "priority": "-1", "uri": "extending.html", "dispname": "Extending"}, "154": {"name": "extending-metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Metadata"}, "155": {"name": "field", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-$", "dispname": "-"}, "156": {"name": "genindex", "domain": "std", "role": "label", "priority": "-1", "uri": "genindex.html", "dispname": "Index"}, "157": {"name": "glossary", "domain": "std", "role": "doc", "priority": "-1", "uri": "glossary.html", "dispname": "Glossary"}, "158": {"name": "hashing", "domain": "std", "role": "doc", "priority": "-1", "uri": "hashing.html", "dispname": "Hashing"}, "159": {"name": "helpers", "domain": "std", "role": "label", "priority": "-1", "uri": "api.html#$", "dispname": "Helpers"}, "160": {"name": "how", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "How Does It Work?"}, "161": {"name": "how-does-it-work", "domain": "std", "role": "doc", "priority": "-1", "uri": "how-does-it-work.html", "dispname": "How Does It Work?"}, "162": {"name": "how-frozen", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#$", "dispname": "Immutability"}, "163": {"name": "how-slotted-cached_property", "domain": "std", "role": "label", "priority": "-1", "uri": "how-does-it-work.html#how-slotted-cached-property", "dispname": "Cached Properties on Slotted Classes"}, "164": {"name": "index", "domain": "std", "role": "doc", "priority": "-1", "uri": "index.html", "dispname": "attrs: Classes Without Boilerplate"}, "165": {"name": "init", "domain": "std", "role": "doc", "priority": "-1", "uri": "init.html", "dispname": "Initialization"}, "166": {"name": "init-subclass", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "attrs and __init_subclass__"}, "167": {"name": "license", "domain": "std", "role": "doc", "priority": "-1", "uri": "license.html", "dispname": "License and Credits"}, "168": {"name": "metadata", "domain": "std", "role": "label", "priority": "-1", "uri": "examples.html#$", "dispname": "Metadata"}, "169": {"name": "modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Module Index"}, "170": {"name": "names", "domain": "std", "role": "doc", "priority": "-1", "uri": "names.html", "dispname": "On The Core API Names"}, "171": {"name": "overview", "domain": "std", "role": "doc", "priority": "-1", "uri": "overview.html", "dispname": "Overview"}, "172": {"name": "private-attributes", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Private Attributes and Aliases"}, "173": {"name": "py-modindex", "domain": "std", "role": "label", "priority": "-1", "uri": "py-modindex.html", "dispname": "Python Module Index"}, "174": {"name": "search", "domain": "std", "role": "label", "priority": "-1", "uri": "search.html", "dispname": "Search Page"}, "175": {"name": "slotted classes", "domain": "std", "role": "term", "priority": "-1", "uri": "glossary.html#term-slotted-classes", "dispname": "-"}, "176": {"name": "transform-fields", "domain": "std", "role": "label", "priority": "-1", "uri": "extending.html#$", "dispname": "Automatic Field Transformation and Modification"}, "177": {"name": "types", "domain": "std", "role": "doc", "priority": "-1", "uri": "types.html", "dispname": "Type Annotations"}, "178": {"name": "validators", "domain": "std", "role": "label", "priority": "-1", "uri": "init.html#$", "dispname": "Validators"}, "179": {"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 50cf9464..a81d2965 100644 --- a/tests/resource/objects_attrs.txt +++ b/tests/resource/objects_attrs.txt @@ -1,29 +1,27 @@ # Sphinx inventory version 2 # Project: attrs -# Version: 22.1 +# Version: 25.4 # The remainder of this file is compressed using zlib. -attr py:module 0 index.html#module-$ - -attr.VersionInfo py:class 1 api.html#$ - +attr py:module 0 api-attr.html#module-$ - +attr.Attribute py:class 1 api-attr.html#$ - +attr.NOTHING py:data 1 api-attr.html#$ - +attr.VersionInfo py:class 1 api-attr.html#$ - attr._make.Attribute py:class -1 api.html#attrs.Attribute - +attr._make.ClassProps py:class -1 api.html#attrs.ClassProps - +attr._make.ClassProps.Hashability py:class -1 api.html#attrs.ClassProps.Hashability - +attr._make.ClassProps.KeywordOnly py:class -1 api.html#attrs.ClassProps.KeywordOnly - +attr._make.Converter py:class -1 api.html#attrs.Converter - 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.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._version_info.VersionInfo py:class -1 api-attr.html#attr.VersionInfo - +attr.asdict py:function 1 api-attr.html#$ - +attr.assoc py:function 1 api-attr.html#$ - +attr.astuple py:function 1 api-attr.html#$ - +attr.attrs py:function 1 api-attr.html#$ - +attr.cmp_using py:function 1 api-attr.html#$ - +attr.converters py:module 0 api-attr.html#module-$ - +attr.define py:function 1 api-attr.html#$ - +attr.evolve py:function 1 api-attr.html#$ - +attr.exceptions py:module 0 api-attr.html#module-$ - 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 - @@ -33,27 +31,67 @@ attr.exceptions.NotAnAttrsClassError py:exception -1 api.html#attrs.exceptions.N 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.ib 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#$ - -attrs py:module 0 index.html#module-$ - +attr.field py:function 1 api-attr.html#$ - +attr.fields py:function 1 api-attr.html#$ - +attr.fields_dict py:function 1 api-attr.html#$ - +attr.filters py:module 0 api-attr.html#module-$ - +attr.filters.exclude py:function 1 api-attr.html#$ - +attr.filters.include py:function 1 api-attr.html#$ - +attr.frozen py:function 1 api-attr.html#$ - +attr.get_run_validators py:function 1 api-attr.html#$ - +attr.has py:function 1 api-attr.html#$ - +attr.ib py:function 1 api-attr.html#$ - +attr.make_class py:function 1 api-attr.html#$ - +attr.mutable py:function 1 api-attr.html#$ - +attr.resolve_types py:function 1 api-attr.html#$ - +attr.s py:function 1 api-attr.html#$ - +attr.set_run_validators py:function 1 api-attr.html#$ - +attr.setters py:module 0 api-attr.html#module-$ - +attr.validate py:function 1 api-attr.html#$ - +attr.validators py:module 0 api-attr.html#module-$ - +attrs py:module 0 api.html#module-$ - attrs.Attribute py:class 1 api.html#$ - attrs.Attribute.evolve py:method 1 api.html#$ - +attrs.ClassProps py:class 1 api.html#$ - +attrs.ClassProps.Hashability py:class 1 api.html#$ - +attrs.ClassProps.Hashability.HASHABLE py:attribute 1 api.html#$ - +attrs.ClassProps.Hashability.HASHABLE_CACHED py:attribute 1 api.html#$ - +attrs.ClassProps.Hashability.LEAVE_ALONE py:attribute 1 api.html#$ - +attrs.ClassProps.Hashability.UNHASHABLE py:attribute 1 api.html#$ - +attrs.ClassProps.KeywordOnly py:class 1 api.html#$ - +attrs.ClassProps.KeywordOnly.FORCE py:attribute 1 api.html#$ - +attrs.ClassProps.KeywordOnly.NO py:attribute 1 api.html#$ - +attrs.ClassProps.KeywordOnly.YES py:attribute 1 api.html#$ - +attrs.ClassProps.added_eq py:attribute 1 api.html#$ - +attrs.ClassProps.added_init py:attribute 1 api.html#$ - +attrs.ClassProps.added_match_args py:attribute 1 api.html#$ - +attrs.ClassProps.added_ordering py:attribute 1 api.html#$ - +attrs.ClassProps.added_pickling py:attribute 1 api.html#$ - +attrs.ClassProps.added_repr py:attribute 1 api.html#$ - +attrs.ClassProps.added_str py:attribute 1 api.html#$ - +attrs.ClassProps.collected_fields_by_mro py:attribute 1 api.html#$ - +attrs.ClassProps.field_transformer py:attribute 1 api.html#$ - +attrs.ClassProps.has_weakref_slot py:attribute 1 api.html#$ - +attrs.ClassProps.hashability py:attribute 1 api.html#$ - +attrs.ClassProps.is_exception py:attribute 1 api.html#$ - +attrs.ClassProps.is_frozen py:attribute 1 api.html#$ - +attrs.ClassProps.is_slotted py:attribute 1 api.html#$ - +attrs.ClassProps.kw_only py:attribute 1 api.html#$ - +attrs.ClassProps.on_setattr_hook py:attribute 1 api.html#$ - +attrs.Converter py:class 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 py:module 0 api.html#module-$ - 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 py:module 0 api.html#module-$ - attrs.exceptions.AttrsAttributeNotFoundError py:exception 1 api.html#$ - attrs.exceptions.DefaultAlreadySetError py:exception 1 api.html#$ - attrs.exceptions.FrozenAttributeError py:exception 1 api.html#$ - @@ -66,16 +104,23 @@ 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 py:module 0 api.html#module-$ - attrs.filters.exclude py:function 1 api.html#$ - attrs.filters.include py:function 1 api.html#$ - +attrs.frozen py:function 1 api.html#$ - attrs.has py:function 1 api.html#$ - +attrs.inspect py:function 1 api.html#$ - attrs.make_class py:function 1 api.html#$ - +attrs.mutable py:function 1 api.html#$ - attrs.resolve_types py:function 1 api.html#$ - +attrs.setters py:module 0 api.html#module-$ - +attrs.setters.NO_OP py:data 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 py:module 0 api.html#module-$ - 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#$ - @@ -91,23 +136,28 @@ 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.not_ py:function 1 api.html#$ - attrs.validators.optional py:function 1 api.html#$ - -attrs.validators.provides py:function 1 api.html#$ - +attrs.validators.or_ py:function 1 api.html#$ - attrs.validators.set_disabled py:function 1 api.html#$ - api std:doc -1 api.html API Reference +api-attr std:doc -1 api-attr.html API Reference for the attr Namespace +api-validators std:label -1 api.html#$ Validators 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 +attribute std:term -1 glossary.html#term-$ - changelog std:doc -1 changelog.html Changelog comparison std:doc -1 comparison.html Comparison converters std:label -1 init.html#$ Converters custom-comparison std:label -1 comparison.html#$ Customization +defaults std:label -1 init.html#$ Defaults 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 +examples-validators std:label -1 examples.html#$ Validators extending std:doc -1 extending.html Extending -extending_metadata std:label -1 extending.html#extending-metadata Metadata +extending-metadata std:label -1 extending.html#$ Metadata +field std:term -1 glossary.html#term-$ - genindex std:label -1 genindex.html Index glossary std:doc -1 glossary.html Glossary hashing std:doc -1 hashing.html Hashing @@ -115,19 +165,20 @@ 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 +how-slotted-cached_property std:label -1 how-does-it-work.html#how-slotted-cached-property Cached Properties on Slotted Classes index std:doc -1 index.html attrs: Classes Without Boilerplate init std:doc -1 init.html Initialization +init-subclass std:label -1 init.html#$ attrs and __init_subclass__ 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 +private-attributes std:label -1 init.html#$ Private Attributes and Aliases py-modindex std:label -1 py-modindex.html Python Module Index search std:label -1 search.html Search Page 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… diff --git a/tests/resource/objects_attrs_22_1.inv b/tests/resource/objects_attrs_22_1.inv new file mode 100644 index 00000000..85189bdf Binary files /dev/null and b/tests/resource/objects_attrs_22_1.inv differ diff --git a/tests/resource/objects_sphinx.inv b/tests/resource/objects_sphinx.inv index ed2fe5b4..7a4f085b 100644 Binary files a/tests/resource/objects_sphinx.inv and b/tests/resource/objects_sphinx.inv differ diff --git a/tests/resource/objects_sphinx_6_0b.inv b/tests/resource/objects_sphinx_6_0b.inv new file mode 100644 index 00000000..ed2fe5b4 Binary files /dev/null and b/tests/resource/objects_sphinx_6_0b.inv differ diff --git a/tests/test_api_fail.py b/tests/test_api_fail.py index d77088f4..786ca49b 100644 --- a/tests/test_api_fail.py +++ b/tests/test_api_fail.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_api_good.py b/tests/test_api_good.py index 8193306b..d746bff1 100644 --- a/tests/test_api_good.py +++ b/tests/test_api_good.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -115,19 +115,19 @@ def test_api_decompress(self, path_fxn, scratch_path, misc_info, decomp_cmp_test soi.DataFields.Domain: b"py", soi.DataFields.Role: b"module", soi.DataFields.Priority: b"0", - soi.DataFields.URI: b"index.html#module-$", + soi.DataFields.URI: b"api-attr.html#module-$", soi.DataFields.DispName: b"-", }, ], [ -3, { # slots std:label -1 examples.html#$ Slots - soi.DataFields.Name: b"validators", + soi.DataFields.Name: b"types", soi.DataFields.Domain: b"std", - soi.DataFields.Role: b"label", + soi.DataFields.Role: b"doc", soi.DataFields.Priority: b"-1", - soi.DataFields.URI: b"init.html#$", - soi.DataFields.DispName: b"Validators", + soi.DataFields.URI: b"types.html", + soi.DataFields.DispName: b"Type Annotations", }, ], ), @@ -136,7 +136,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)) == 129 + assert len(soi.re.pb_data.findall(bytes_txt)) == 180 mchs = list(soi.re.pb_data.finditer(bytes_txt)) @@ -448,12 +448,12 @@ def test_api_inventory_toosmallflatdict_importbutignore(self, res_dec): inv2 = soi.Inventory(d, count_error=False) # 128 (one less than 129) b/c the loop continues past missing elements - assert inv2.count == 128 + assert inv2.count == 179 def test_api_inventory_namesuggest(self, res_cmp, check): """Confirm object name suggestion is nominally working on a specific object.""" - rst = ":py:function:`attr.attr.evolve`" - idx = 10 + rst = ":py:function:`attr.evolve`" + idx = 18 inv = soi.Inventory(str(res_cmp)) @@ -584,7 +584,26 @@ def test_api_inventory_matches_sphinx_ifile( original_ifile_data ), fname - elif "sphinx.inv" in fname: # pragma: no cover + elif re.search(r"sphinx(|_6_0b)[.]inv", fname): # pragma: no cover + soi_names = [o.name for o in inv.objects] + ifile_names = list( + itt.chain.from_iterable( + list(original_ifile_data[k].keys()) for k in original_ifile_data + ) + ) + + # There is the same set of unique names in the sphobjinv Inventory + # as in the Sphinx IFile imported data ... + assert set(soi_names) == set(ifile_names), fname + + # ... but there are duplicate names in each ... + assert inv.count > len(set(soi_names)), fname + assert sphinx_ifile_data_count(original_ifile_data) > len( + set(ifile_names) + ), fname + + # ... and there are always four more items in the sphobjinv Inventory + # than in the IFile data. assert inv.count == 4 + sphinx_ifile_data_count(original_ifile_data), fname else: diff --git a/tests/test_api_good_nonlocal.py b/tests/test_api_good_nonlocal.py index eec40738..5d267f93 100644 --- a/tests/test_api_good_nonlocal.py +++ b/tests/test_api_good_nonlocal.py @@ -10,7 +10,7 @@ 21 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_cli.py b/tests/test_cli.py index 8dd367e7..06ade7ed 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv @@ -355,7 +355,7 @@ 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+82\\s*$", out_.getvalue(), re.M) + assert re.search("^.*instance_of\\S*\\s+127\\s*$", out_.getvalue(), re.M) @pytest.mark.timeout(CLI_TEST_TIMEOUT) def test_cli_suggest_withscore(self, run_cmdline_test, res_cmp): @@ -373,7 +373,7 @@ def test_cli_suggest_withscoreandindex(self, run_cmdline_test, res_cmp): @pytest.mark.parametrize( ["inp", "flags", "nlines"], - [("", "-at", 129), ("y\n", "-t", 130), ("n\n", "-t", 1)], + [("", "-at", 180), ("y\n", "-t", 181), ("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): diff --git a/tests/test_cli_nonlocal.py b/tests/test_cli_nonlocal.py index f074e86b..064733ff 100644 --- a/tests/test_cli_nonlocal.py +++ b/tests/test_cli_nonlocal.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_cli_textconv.py b/tests/test_cli_textconv.py index 3ad39cc8..f08356f5 100644 --- a/tests/test_cli_textconv.py +++ b/tests/test_cli_textconv.py @@ -10,7 +10,7 @@ 22 Dec 2025 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_fixture.py b/tests/test_fixture.py index a48cb98d..0760ddff 100644 --- a/tests/test_fixture.py +++ b/tests/test_fixture.py @@ -10,7 +10,7 @@ 20 Mar 2019 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_flake8_ext.py b/tests/test_flake8_ext.py deleted file mode 100644 index 8604d12c..00000000 --- a/tests/test_flake8_ext.py +++ /dev/null @@ -1,73 +0,0 @@ -r"""*Test(s) to ensure full loading of flake8 extensions*. - -``sphobjinv`` is a toolkit for manipulation and inspection of -Sphinx |objects.inv| files. - -**Author** - Brian Skinn (brian.skinn@gmail.com) - -**File Created** - 27 Apr 2019 - -**Copyright** - \(c) Brian Skinn 2016-2025 - -**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 re -import subprocess as sp # noqa: S404 -import sys -from pathlib import Path - -import pytest - -pytestmark = [pytest.mark.flake8_ext] - - -@pytest.fixture(scope="module", autouse=True) -def skip_if_no_flake8_ext(pytestconfig): - """Skip test if --flake8_ext not provided. - - Auto-applied to all functions in module. - - """ - if not pytestconfig.getoption("--flake8_ext"): - pytest.skip("'--flake8_ext' not specified") # pragma: no cover - - -@pytest.mark.skipif( - sys.version_info < (3, 6), - reason="Some flake8 extensions require Python 3.6 or later", -) -def test_flake8_version_output(check): - """Confirm that all desired plugins actually report as loaded.""" - p_pkgname = re.compile("^[0-9a-z_-]+", re.I) - plugins = Path("requirements-flake8.txt").read_text().splitlines()[1:] - plugins = [p_pkgname.search(p).group(0) for p in plugins] - - # This is fragile if anything ends up not having a prefix that needs - # stripping - plugins = [p.partition("flake8-")[-1] for p in plugins] - - flake8_ver_output = sp.check_output( # noqa: S607,S603 - ["flake8", "--version"], universal_newlines=True - ) # noqa: S607,S603 - - for p in plugins: - with check(msg=p): - assert p in flake8_ver_output.replace("_", "-").replace("\n", "") diff --git a/tests/test_intersphinx.py b/tests/test_intersphinx.py index 4096c0c4..7d72739f 100644 --- a/tests/test_intersphinx.py +++ b/tests/test_intersphinx.py @@ -10,7 +10,7 @@ 21 Jun 2022 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tests/test_valid_objects.py b/tests/test_valid_objects.py index 6367dde8..b934394b 100644 --- a/tests/test_valid_objects.py +++ b/tests/test_valid_objects.py @@ -10,7 +10,7 @@ 13 Feb 2021 **Copyright** - \(c) Brian Skinn 2016-2025 + \(c) 2016-2026 Brian Skinn and community contributors **Source Repository** https://github.com/bskinn/sphobjinv diff --git a/tox.ini b/tox.ini index b0366da9..47857a09 100644 --- a/tox.ini +++ b/tox.ini @@ -11,11 +11,13 @@ envlist= # Scan attrs versions py313-sphx_latest-attrs_{19_2,19_3,20_3,21_3,22_2,23_2,24_3,dev}-jsch_latest # Scan jsonschema versions - py313-sphx_latest-attrs_latest-jsch_{3_0,3_x,4_0,4_8,4_14,4_20,dev} + py313-sphx_latest-attrs_latest-jsch_{3_1_1,3_x,4_0,4_8,4_14,4_20,dev} # Earliest supported Python and lib versions all together - py310-sphx_1_6_x-attrs_19_2-jsch_3_0 + py310-sphx_1_6_x-attrs_19_2-jsch_3_1_1 # Spot matrix of early Python, Sphinx, attrs versions py3{10,11}-sphx_{1,2}_x-attrs_{19,20}_2-jsch_latest + # Test the new-earliest jsonschema version that started failing in 3.13 + py3{10,11,12,13,14}-sphx_latest-attrs_latest-jsch_3_1_1 # Test the specific Sphinx threshold cases where behavior changed py313-sphx_{2_3_1,2_4_0,3_2_1,3_3_0,3_4_0,8_1_3,8_2_0}-attrs_latest-jsch_latest # Simple 'does the sdist install' check @@ -63,7 +65,7 @@ deps= attrs_latest: attrs attrs_dev: git+https://github.com/python-attrs/attrs - jsch_3_0: jsonschema==3.0 + jsch_3_1_1: jsonschema==3.1.1 jsch_3_x: jsonschema<4 jsch_4_0: jsonschema<4.1 jsch_4_8: jsonschema<4.9 @@ -150,6 +152,16 @@ commands= python -Werror -c "import sphobjinv" deps= +[testenv:build] +skip_install=True +description=Build sdist and wheel +deps= + build + twine +commands= + python -m build + twine check dist/* + [pytest] markers = local: Tests not requiring Internet access @@ -160,7 +172,6 @@ markers = intersphinx: Tests on intersphinx-related functionality fixture: Trivial tests for test suite fixtures testall: Tests that use *all* objects_xyz.inv files in tests/resource, if --testall is specified - flake8_ext: Test checking that all desired plugins are active first: Inherited marker from `pytest-ordering` timeout: Inherited marker from `pytest-timeout`