diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 2973de69c..9173dd4e0 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -8,7 +8,7 @@ jobs: name: "Benchmark time & memory" runs-on: "ubuntu-latest" steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set Up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d399253fc..8b7c0b010 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,7 +23,7 @@ jobs: sphinx-version: "4.5.0" docutils-version: "0.15" steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set Up Python ${{ matrix.python-version }} uses: actions/setup-python@v4 with: @@ -50,7 +50,7 @@ jobs: name: Lint runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.8 uses: actions/setup-python@v4 with: diff --git a/.github/workflows/docker.yaml b/.github/workflows/docker.yaml index ed8258380..42bb60ab7 100644 --- a/.github/workflows/docker.yaml +++ b/.github/workflows/docker.yaml @@ -31,14 +31,14 @@ jobs: steps: # Checks-out your repository under $GITHUB_WORKSPACE - name: Checkout 🛎️ - uses: actions/checkout@v3.5.3 + uses: actions/checkout@v4 - name: Set up Docker Build 🐋 - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@v3 - name: Extract metadata (tags, labels) for Docker id: meta - uses: docker/metadata-action@v4 + uses: docker/metadata-action@v5 with: images: | ${{ secrets.DOCKERHUB_USERNAME }}/${{ matrix.image }} @@ -56,14 +56,14 @@ jobs: - # Login to Docker Hub Docker Registry for deployment name: Login to Docker Hub Docker Registry 🐸 - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push html image to Doker Hub Docker Registry 🐳 id: docker_build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: push: ${{ github.event_name != 'pull_request' && steps.deploycheck.outputs.value == 'y' }} file: docker/Dockerfile diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 42390fd39..ae2c02aa2 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -7,7 +7,7 @@ jobs: name: Docs-Linkcheck runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set Up Python uses: actions/setup-python@v4 with: diff --git a/.github/workflows/js_test.yml b/.github/workflows/js_test.yml index 69bf86aed..b78a08297 100644 --- a/.github/workflows/js_test.yml +++ b/.github/workflows/js_test.yml @@ -12,7 +12,7 @@ jobs: uses: actions/setup-node@v3 with: node-version: 18 - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Update pip run: | pip install -U wheel diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 6197a97ce..9ea325cba 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -8,7 +8,7 @@ jobs: name: Build packages runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v4 with: @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest needs: build steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v4 with: @@ -55,7 +55,7 @@ jobs: runs-on: ubuntu-latest needs: publish_test steps: - - uses: actions/checkout@v3.5.3 + - uses: actions/checkout@v4 - name: Set up Python 3.9 uses: actions/setup-python@v4 with: diff --git a/.readthedocs.yml b/.readthedocs.yml index b156c2885..dfe091dfa 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -2,6 +2,8 @@ version: 2 sphinx: configuration: docs/conf.py + builder: html + fail_on_warning: true python: install: diff --git a/docs/builders.rst b/docs/builders.rst index 52e37fc43..ee3acbf7b 100644 --- a/docs/builders.rst +++ b/docs/builders.rst @@ -163,3 +163,21 @@ or .. hint:: As an alternative, you can set the config option :ref:`needs_build_needumls` to export the needumls files during each build. + + +.. _needs_id_builder: + +needs_id +-------- +.. versionadded:: 1.4.0 + +The **needs_id** builder exports all found needs and selected filter results to a set json files of each need with the name is ``id`` of need. + +The build creates a folder called :ref:``needs_build_json_per_id_path`` and all file json of each need inside the given build-folder. + +Usage ++++++ + +.. code-block:: bash + + sphinx-build -b needs_id source_dir build_dir \ No newline at end of file diff --git a/docs/changelog.rst b/docs/changelog.rst index 1f22c0d73..60ecad8d9 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -7,7 +7,7 @@ License ------- .. include:: ../LICENSE - + 2.0.0 ----- Released: under development @@ -16,11 +16,13 @@ Released: under development ----- Released: under development +* Improvement: Added Builder :ref:`needs_id_builder` added and config option :ref:`needs_build_json_per_id` in `conf.py`. * Improvement: Reduce document build time, by memoizing the inline parse in ``build_need`` (`#968 `_) - * Change `NeedsBuilder` format to `needs` (`#978 `_) - * Improvement: Suffix all warnings with ``[needs]``, and allow them to be suppressed (`#975 `_) +* Improvement: :ref:`needextend` for single needs is much faster. +* Improvement: General performance improvement (up to 50%) and less memory consumption (~40%). +* Improvement: external_needs is using cached templates to save generation time. * Bugfix: Check filter strings for correctness. (`#964 `_) @@ -916,3 +918,5 @@ custom css definitions you need to update them. * Integrated interaction with the activated plantuml sphinx extension * Added role **need** to create a reference to a need by giving the id + + diff --git a/docs/conf.py b/docs/conf.py index 07abd022c..08a5646b6 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -62,6 +62,13 @@ "sphinx": ("https://www.sphinx-doc.org/en/master", None), } +nitpicky = True +nitpick_ignore = [ + ("py:class", "T"), + ("py:class", "sphinx_needs.debug.T"), + ("py:class", "sphinx_needs.data.NeedsInfoType"), +] + # smartquotes = False needs_debug_measurement = True @@ -361,6 +368,9 @@ def custom_defined_func(): # build needs.json to make permalinks work needs_build_json = True +# build needs_json for every needs-id to make detail panel +needs_build_json_per_id = False + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] diff --git a/docs/configuration.rst b/docs/configuration.rst index 6cb9532ed..ad230cae1 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -1792,6 +1792,50 @@ Example: The created ``needs.json`` file gets stored in the ``outdir`` of the current builder. So if ``html`` is used as builder, the final location is e.g. ``_build/html/needs.json``. + +.. _needs_build_json_per_id: + +needs_build_json_per_id +~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.4.0 + +Builds list json files for each need. The name of each file is the ``id`` of need. +This option works like :ref:`needs_build_json`. + +Default: False + +Example: + +.. code-block:: python + + needs_build_json_per_id = False + +.. hint:: + + The created single json file per need, located in :ref:`needs_build_json_per_id_path` folder, e.g ``_build/needs_id/abc_432.json`` + +.. _needs_build_json_per_id_path: + +needs_build_json_per_id_path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. versionadded:: 1.4.0 + +This option sets the location of the set of ``needs.json`` for every needs-id. + +Default value: ``needs_id`` + +Example: + +.. code-block:: python + + needs_build_json_per_id_path = "needs_id" + +.. hint:: + + The created ``needs_id`` folder gets stored in the ``outdir`` of the current builder. The final location is e.g. ``_build/needs_id`` + .. _needs_build_needumls: needs_build_needumls @@ -1895,6 +1939,22 @@ constraints_passed is a bool showing if ALL constraints of a corresponding need constraints_results is a dictionary similar in structure to needs_constraints above. Instead of executable python statements, inner values contain a bool describing if check_0, check_1 ... passed successfully. +.. versionadded:: 1.4.0 + + The ``"error_message"`` key can contain a string, with Jinja templating, which will be displayed if the constraint fails, and saved on the need as ``constraints_error``: + + .. code-block:: python + + needs_constraints = { + + "critical": { + "check_0": "'critical' in tags", + "severity": "CRITICAL", + "error_message": "need {% raw %}{{id}}{% endraw %} does not fulfill CRITICAL constraint, because tags are {% raw %}{{tags}}{% endraw %}" + } + + } + .. code-block:: rst diff --git a/docs/contributing.rst b/docs/contributing.rst index 4e6777650..7a06e5a22 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -56,6 +56,7 @@ installed in an isolated environment by Poetry. List make targets ----------------- + **Sphinx-Needs** uses ``make`` to invoke most development related actions. Use ``make list`` to get a list of available targets. @@ -92,20 +93,45 @@ To check if all used links in the documentation are still valid, run: Running Tests ------------- -.. hint:: - Please be sure to have the dependencies of the official documentation installed: +You can either run the tests directly using ``pytest``, in an existing environment: + +.. code-block:: bash + + pytest tests/ + +Or you can use the provided Makefile: .. code-block:: bash - pip install -r docs/requirements.txt make test +Note some tests use `syrupy `__ to perform snapshot testing. +These snapshots can be updated by running: + +.. code-block:: bash + + pytest tests/ --snapshot-update + +.. hint:: + + Please be sure to have the dependencies of the official documentation also installed: + + .. code-block:: bash + + pip install -r docs/requirements.txt + Linting & Formatting -------------------- -**Sphinx-Needs** uses `black `_ and -`isort `_ to format its source code. +**Sphinx-Needs** uses `pre-commit `__ to run formatting and checking of source code. +This can be run directly using: + +.. code-block:: bash + + pre-commit run --all-files + +or via the provided Makefile: .. code-block:: bash @@ -182,5 +208,66 @@ The release jobs will build the source and wheel distribution and try to upload to ``test.pypi.org`` and ``pypy.org``. +Structure of the extension's logic +---------------------------------- + +The following is an outline of the build events which this extension adds to the :ref:`Sphinx build process `: + +#. After configuration has been initialised (``config-inited`` event): + + - Register additional directives, directive options and warnings (``load_config``) + - Check configuration consistency (``check_configuration``) + +#. Before reading changed documents (``env-before-read-docs`` event): + + - Initialise ``BuildEnvironment`` variables (``prepare_env``) + - Register services (``prepare_env``) + - Register functions (``prepare_env``) + - Initialise default extra options (``prepare_env``) + - Initialise extra link types (``prepare_env``) + - Ensure default configurations are set (``prepare_env``) + - Start process timing, if enabled (``prepare_env``) + - Load external needs (``load_external_needs``) + +#. For all removed and changed documents (``env-purge-doc`` event): + + - Remove all cached need items that originate from the document (``purge_needs``) + +#. For changed documents (``doctree-read`` event, priority 880 of transforms) + + - Determine and add data on parent sections and needs(``analyse_need_locations``) + - Remove ``Need`` nodes marked as ``hidden`` (``analyse_need_locations``) + +#. When building in parallel mode (``env-merge-info`` event), merge ``BuildEnvironment`` data (``merge_data``) + +#. After all documents have been read and transformed (``env-updated`` event) (NOTE these are skipped for ``needs`` builder) + + - Copy vendored JS libraries (with CSS) to build folder (``install_lib_static_files``) + - Generate permalink file (``install_permalink_file``) + - Copy vendored CSS files to build folder (``install_styles_static_files``) + +#. Note, the ``BuildEnvironment`` is cached at this point, only if any documents were updated. + +#. For all changed documents, or their dependants (``doctree-resolved``) + + - Replace all ``Needextract`` nodes with a list of the collected ``Need`` (``process_creator``) + - Remove all ``Need`` nodes, if ``needs_include_needs`` is ``True`` (``process_need_nodes``) + - Call dynamic functions, set as values on the need data items and replace them with their return values (``process_need_nodes -> resolve_dynamic_values``) + - Replace needs data variant values (``process_need_nodes -> resolve_variants_options``) + - Check for dead links (``process_need_nodes -> check_links``) + - Generate back links (``process_need_nodes -> create_back_links``) + - Process constraints, for each ``Need`` node (``process_need_nodes -> process_constraints``) + - Perform all modifications on need data items, due to ``Needextend`` nodes (``process_need_nodes -> extend_needs_data``) + - Format each ``Need`` node to give the desired visual output (``process_need_nodes -> print_need_nodes``) + - Process all other need specific nodes, replacing them with the desired visual output (``process_creator``) + +#. At the end of the build (``build-finished`` event) + + - Call all user defined need data checks, a.k.a `needs_warnings` (``process_warnings``) + - Write the ``needs.json`` to the output folder, if `needs_build_json = True` (``build_needs_json``) + - Write the ``needs.json`` per ID to the output folder, if `needs_build_json_per_id = True` (``build_needs_id_json``) + - Write all UML files to the output folder, if `needs_build_needumls = True` (``build_needumls_pumls``) + - Print process timing, if `needs_debug_measurement = True` (``process_timing``) + .. Include our contributors and maintainers. .. include:: ../AUTHORS diff --git a/docs/directives/need.rst b/docs/directives/need.rst index e41291aa6..c671e7128 100644 --- a/docs/directives/need.rst +++ b/docs/directives/need.rst @@ -358,10 +358,12 @@ By using :ref:`needs_extra_links `, you can use the configure { "option": "blocks", "incoming": "is blocked by", + "outgoing": "blocks" }, { "option": "tests", "incoming": "is tested by", + "outgoing": "tests", "copy": False, "color": "#00AA00" } diff --git a/docs/requirements.txt b/docs/requirements.txt index 633d78ae6..ed19d3bf9 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -7,4 +7,4 @@ sphinxcontrib-programoutput sphinx-design click tabulate -sphinx-immaterial==0.11.6 +sphinx-immaterial==0.11.7 diff --git a/noxfile.py b/noxfile.py index 85f54d0cb..e9b3ffddf 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,6 +14,7 @@ TEST_DEPENDENCIES = [ "pytest", "pytest-xdist", + "syrupy", "responses", "lxml", "pyparsing!=3.0.4", diff --git a/poetry.lock b/poetry.lock index e2a68f25a..af90bc526 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,10 +1,9 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. [[package]] name = "alabaster" version = "0.7.13" description = "A configurable sidebar-enabled Sphinx theme" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -14,43 +13,43 @@ files = [ [[package]] name = "attrs" -version = "22.2.0" +version = "23.1.0" description = "Classes Without Boilerplate" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] +[package.dependencies] +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + [package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] [[package]] name = "babel" -version = "2.11.0" +version = "2.12.1" description = "Internationalization utilities" -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Babel-2.11.0-py3-none-any.whl", hash = "sha256:1ad3eca1c885218f6dce2ab67291178944f810a10a9b5f3cb8382a5a232b64fe"}, - {file = "Babel-2.11.0.tar.gz", hash = "sha256:5ef4b3226b0180dedded4229651c8b0e1a3a6a2837d45a073272f313e4cf97f6"}, + {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, + {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, ] [package.dependencies] -pytz = ">=2015.7" +pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} [[package]] name = "black" version = "22.12.0" description = "The uncompromising code formatter." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -85,21 +84,19 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.7.22" description = "Python package for providing Mozilla's CA Bundle." -category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, + {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, ] [[package]] name = "cfgv" version = "3.3.1" description = "Validate configuration and produce human readable error messages." -category = "dev" optional = false python-versions = ">=3.6.1" files = [ @@ -109,112 +106,97 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.0.1" +version = "3.2.0" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." -category = "main" optional = false -python-versions = "*" +python-versions = ">=3.7.0" files = [ - {file = "charset-normalizer-3.0.1.tar.gz", hash = "sha256:ebea339af930f8ca5d7a699b921106c6e29c617fe9606fa7baa043c1cdae326f"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88600c72ef7587fe1708fd242b385b6ed4b8904976d5da0893e31df8b3480cb6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c75ffc45f25324e68ab238cb4b5c0a38cd1c3d7f1fb1f72b5541de469e2247db"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:db72b07027db150f468fbada4d85b3b2729a3db39178abf5c543b784c1254539"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62595ab75873d50d57323a91dd03e6966eb79c41fa834b7a1661ed043b2d404d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ff6f3db31555657f3163b15a6b7c6938d08df7adbfc9dd13d9d19edad678f1e8"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:772b87914ff1152b92a197ef4ea40efe27a378606c39446ded52c8f80f79702e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70990b9c51340e4044cfc394a81f614f3f90d41397104d226f21e66de668730d"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:292d5e8ba896bbfd6334b096e34bffb56161c81408d6d036a7dfa6929cff8783"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:2edb64ee7bf1ed524a1da60cdcd2e1f6e2b4f66ef7c077680739f1641f62f555"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:31a9ddf4718d10ae04d9b18801bd776693487cbb57d74cc3458a7673f6f34639"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:44ba614de5361b3e5278e1241fda3dc1838deed864b50a10d7ce92983797fa76"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:12db3b2c533c23ab812c2b25934f60383361f8a376ae272665f8e48b88e8e1c6"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c512accbd6ff0270939b9ac214b84fb5ada5f0409c44298361b2f5e13f9aed9e"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win32.whl", hash = "sha256:502218f52498a36d6bf5ea77081844017bf7982cdbe521ad85e64cabee1b608b"}, - {file = "charset_normalizer-3.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:601f36512f9e28f029d9481bdaf8e89e5148ac5d89cffd3b05cd533eeb423b59"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0298eafff88c99982a4cf66ba2efa1128e4ddaca0b05eec4c456bbc7db691d8d"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a8d0fc946c784ff7f7c3742310cc8a57c5c6dc31631269876a88b809dbeff3d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:87701167f2a5c930b403e9756fab1d31d4d4da52856143b609e30a1ce7160f3c"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14e76c0f23218b8f46c4d87018ca2e441535aed3632ca134b10239dfb6dadd6b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0c0a590235ccd933d9892c627dec5bc7511ce6ad6c1011fdf5b11363022746c1"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c7fe7afa480e3e82eed58e0ca89f751cd14d767638e2550c77a92a9e749c317"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:79909e27e8e4fcc9db4addea88aa63f6423ebb171db091fb4373e3312cb6d603"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ac7b6a045b814cf0c47f3623d21ebd88b3e8cf216a14790b455ea7ff0135d18"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:72966d1b297c741541ca8cf1223ff262a6febe52481af742036a0b296e35fa5a"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:f9d0c5c045a3ca9bedfc35dca8526798eb91a07aa7a2c0fee134c6c6f321cbd7"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5995f0164fa7df59db4746112fec3f49c461dd6b31b841873443bdb077c13cfc"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4a8fcf28c05c1f6d7e177a9a46a1c52798bfe2ad80681d275b10dcf317deaf0b"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:761e8904c07ad053d285670f36dd94e1b6ab7f16ce62b9805c475b7aa1cffde6"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win32.whl", hash = "sha256:71140351489970dfe5e60fc621ada3e0f41104a5eddaca47a7acb3c1b851d6d3"}, - {file = "charset_normalizer-3.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:9ab77acb98eba3fd2a85cd160851816bfce6871d944d885febf012713f06659c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:84c3990934bae40ea69a82034912ffe5a62c60bbf6ec5bc9691419641d7d5c9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74292fc76c905c0ef095fe11e188a32ebd03bc38f3f3e9bcb85e4e6db177b7ea"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c95a03c79bbe30eec3ec2b7f076074f4281526724c8685a42872974ef4d36b72"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4c39b0e3eac288fedc2b43055cfc2ca7a60362d0e5e87a637beac5d801ef478"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df2c707231459e8a4028eabcd3cfc827befd635b3ef72eada84ab13b52e1574d"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93ad6d87ac18e2a90b0fe89df7c65263b9a99a0eb98f0a3d2e079f12a0735837"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:59e5686dd847347e55dffcc191a96622f016bc0ad89105e24c14e0d6305acbc6"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:cd6056167405314a4dc3c173943f11249fa0f1b204f8b51ed4bde1a9cd1834dc"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_ppc64le.whl", hash = "sha256:083c8d17153ecb403e5e1eb76a7ef4babfc2c48d58899c98fcaa04833e7a2f9a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_s390x.whl", hash = "sha256:f5057856d21e7586765171eac8b9fc3f7d44ef39425f85dbcccb13b3ebea806c"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:7eb33a30d75562222b64f569c642ff3dc6689e09adda43a082208397f016c39a"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win32.whl", hash = "sha256:95dea361dd73757c6f1c0a1480ac499952c16ac83f7f5f4f84f0658a01b8ef41"}, - {file = "charset_normalizer-3.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:eaa379fcd227ca235d04152ca6704c7cb55564116f8bc52545ff357628e10602"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3e45867f1f2ab0711d60c6c71746ac53537f1684baa699f4f668d4c6f6ce8e14"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cadaeaba78750d58d3cc6ac4d1fd867da6fc73c88156b7a3212a3cd4819d679d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:911d8a40b2bef5b8bbae2e36a0b103f142ac53557ab421dc16ac4aafee6f53dc"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:503e65837c71b875ecdd733877d852adbc465bd82c768a067badd953bf1bc5a3"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a60332922359f920193b1d4826953c507a877b523b2395ad7bc716ddd386d866"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:16a8663d6e281208d78806dbe14ee9903715361cf81f6d4309944e4d1e59ac5b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:a16418ecf1329f71df119e8a65f3aa68004a3f9383821edcb20f0702934d8087"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:9d9153257a3f70d5f69edf2325357251ed20f772b12e593f3b3377b5f78e7ef8"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:02a51034802cbf38db3f89c66fb5d2ec57e6fe7ef2f4a44d070a593c3688667b"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:2e396d70bc4ef5325b72b593a72c8979999aa52fb8bcf03f701c1b03e1166918"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:11b53acf2411c3b09e6af37e4b9005cba376c872503c8f28218c7243582df45d"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win32.whl", hash = "sha256:0bf2dae5291758b6f84cf923bfaa285632816007db0330002fa1de38bfcb7154"}, - {file = "charset_normalizer-3.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:2c03cc56021a4bd59be889c2b9257dae13bf55041a3372d3295416f86b295fb5"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:024e606be3ed92216e2b6952ed859d86b4cfa52cd5bc5f050e7dc28f9b43ec42"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:4b0d02d7102dd0f997580b51edc4cebcf2ab6397a7edf89f1c73b586c614272c"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:358a7c4cb8ba9b46c453b1dd8d9e431452d5249072e4f56cfda3149f6ab1405e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:81d6741ab457d14fdedc215516665050f3822d3e56508921cc7239f8c8e66a58"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8b8af03d2e37866d023ad0ddea594edefc31e827fee64f8de5611a1dbc373174"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9cf4e8ad252f7c38dd1f676b46514f92dc0ebeb0db5552f5f403509705e24753"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e696f0dd336161fca9adbb846875d40752e6eba585843c768935ba5c9960722b"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c22d3fe05ce11d3671297dc8973267daa0f938b93ec716e12e0f6dee81591dc1"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:109487860ef6a328f3eec66f2bf78b0b72400280d8f8ea05f69c51644ba6521a"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:37f8febc8ec50c14f3ec9637505f28e58d4f66752207ea177c1d67df25da5aed"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:f97e83fa6c25693c7a35de154681fcc257c1c41b38beb0304b9c4d2d9e164479"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:a152f5f33d64a6be73f1d30c9cc82dfc73cec6477ec268e7c6e4c7d23c2d2291"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:39049da0ffb96c8cbb65cbf5c5f3ca3168990adf3551bd1dee10c48fce8ae820"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win32.whl", hash = "sha256:4457ea6774b5611f4bed5eaa5df55f70abde42364d498c5134b7ef4c6958e20e"}, - {file = "charset_normalizer-3.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:e62164b50f84e20601c1ff8eb55620d2ad25fb81b59e3cd776a1902527a788af"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eade758719add78ec36dc13201483f8e9b5d940329285edcd5f70c0a9edbd7f"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8499ca8f4502af841f68135133d8258f7b32a53a1d594aa98cc52013fff55678"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3fc1c4a2ffd64890aebdb3f97e1278b0cc72579a08ca4de8cd2c04799a3a22be"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00d3ffdaafe92a5dc603cb9bd5111aaa36dfa187c8285c543be562e61b755f6b"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c2ac1b08635a8cd4e0cbeaf6f5e922085908d48eb05d44c5ae9eabab148512ca"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6f45710b4459401609ebebdbcfb34515da4fc2aa886f95107f556ac69a9147e"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ae1de54a77dc0d6d5fcf623290af4266412a7c4be0b1ff7444394f03f5c54e3"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b590df687e3c5ee0deef9fc8c547d81986d9a1b56073d82de008744452d6541"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab5de034a886f616a5668aa5d098af2b5385ed70142090e2a31bcbd0af0fdb3d"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9cb3032517f1627cc012dbc80a8ec976ae76d93ea2b5feaa9d2a5b8882597579"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:608862a7bf6957f2333fc54ab4399e405baad0163dc9f8d99cb236816db169d4"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:0f438ae3532723fb6ead77e7c604be7c8374094ef4ee2c5e03a3a17f1fca256c"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:356541bf4381fa35856dafa6a965916e54bed415ad8a24ee6de6e37deccf2786"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win32.whl", hash = "sha256:39cf9ed17fe3b1bc81f33c9ceb6ce67683ee7526e65fde1447c772afc54a1bb8"}, - {file = "charset_normalizer-3.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:0a11e971ed097d24c534c037d298ad32c6ce81a45736d31e0ff0ad37ab437d59"}, - {file = "charset_normalizer-3.0.1-py3-none-any.whl", hash = "sha256:7e189e2e1d3ed2f4aebabd2d5b0f931e883676e51c7624826e0a4e5fe8a0bf24"}, + {file = "charset-normalizer-3.2.0.tar.gz", hash = "sha256:3bb3d25a8e6c0aedd251753a79ae98a093c7e7b471faa3aa9a93a81431987ace"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:0b87549028f680ca955556e3bd57013ab47474c3124dc069faa0b6545b6c9710"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7c70087bfee18a42b4040bb9ec1ca15a08242cf5867c58726530bdf3945672ed"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a103b3a7069b62f5d4890ae1b8f0597618f628b286b03d4bc9195230b154bfa9"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94aea8eff76ee6d1cdacb07dd2123a68283cb5569e0250feab1240058f53b623"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:db901e2ac34c931d73054d9797383d0f8009991e723dab15109740a63e7f902a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0dac0ff919ba34d4df1b6131f59ce95b08b9065233446be7e459f95554c0dc8"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:193cbc708ea3aca45e7221ae58f0fd63f933753a9bfb498a3b474878f12caaad"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09393e1b2a9461950b1c9a45d5fd251dc7c6f228acab64da1c9c0165d9c7765c"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:baacc6aee0b2ef6f3d308e197b5d7a81c0e70b06beae1f1fcacffdbd124fe0e3"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:bf420121d4c8dce6b889f0e8e4ec0ca34b7f40186203f06a946fa0276ba54029"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:c04a46716adde8d927adb9457bbe39cf473e1e2c2f5d0a16ceb837e5d841ad4f"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:aaf63899c94de41fe3cf934601b0f7ccb6b428c6e4eeb80da72c58eab077b19a"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62e51710986674142526ab9f78663ca2b0726066ae26b78b22e0f5e571238dd"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win32.whl", hash = "sha256:04e57ab9fbf9607b77f7d057974694b4f6b142da9ed4a199859d9d4d5c63fe96"}, + {file = "charset_normalizer-3.2.0-cp310-cp310-win_amd64.whl", hash = "sha256:48021783bdf96e3d6de03a6e39a1171ed5bd7e8bb93fc84cc649d11490f87cea"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4957669ef390f0e6719db3613ab3a7631e68424604a7b448f079bee145da6e09"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46fb8c61d794b78ec7134a715a3e564aafc8f6b5e338417cb19fe9f57a5a9bf2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f779d3ad205f108d14e99bb3859aa7dd8e9c68874617c72354d7ecaec2a054ac"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f25c229a6ba38a35ae6e25ca1264621cc25d4d38dca2942a7fce0b67a4efe918"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2efb1bd13885392adfda4614c33d3b68dee4921fd0ac1d3988f8cbb7d589e72a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f30b48dd7fa1474554b0b0f3fdfdd4c13b5c737a3c6284d3cdc424ec0ffff3a"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:246de67b99b6851627d945db38147d1b209a899311b1305dd84916f2b88526c6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bd9b3b31adcb054116447ea22caa61a285d92e94d710aa5ec97992ff5eb7cf3"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:8c2f5e83493748286002f9369f3e6607c565a6a90425a3a1fef5ae32a36d749d"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:3170c9399da12c9dc66366e9d14da8bf7147e1e9d9ea566067bbce7bb74bd9c2"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:7a4826ad2bd6b07ca615c74ab91f32f6c96d08f6fcc3902ceeedaec8cdc3bcd6"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:3b1613dd5aee995ec6d4c69f00378bbd07614702a315a2cf6c1d21461fe17c23"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e608aafdb55eb9f255034709e20d5a83b6d60c054df0802fa9c9883d0a937aa"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win32.whl", hash = "sha256:f2a1d0fd4242bd8643ce6f98927cf9c04540af6efa92323e9d3124f57727bfc1"}, + {file = "charset_normalizer-3.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:681eb3d7e02e3c3655d1b16059fbfb605ac464c834a0c629048a30fad2b27489"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c57921cda3a80d0f2b8aec7e25c8aa14479ea92b5b51b6876d975d925a2ea346"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41b25eaa7d15909cf3ac4c96088c1f266a9a93ec44f87f1d13d4a0e86c81b982"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f058f6963fd82eb143c692cecdc89e075fa0828db2e5b291070485390b2f1c9c"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7647ebdfb9682b7bb97e2a5e7cb6ae735b1c25008a70b906aecca294ee96cf4"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eef9df1eefada2c09a5e7a40991b9fc6ac6ef20b1372abd48d2794a316dc0449"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e03b8895a6990c9ab2cdcd0f2fe44088ca1c65ae592b8f795c3294af00a461c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:ee4006268ed33370957f55bf2e6f4d263eaf4dc3cfc473d1d90baff6ed36ce4a"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c4983bf937209c57240cff65906b18bb35e64ae872da6a0db937d7b4af845dd7"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:3bb7fda7260735efe66d5107fb7e6af6a7c04c7fce9b2514e04b7a74b06bf5dd"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:72814c01533f51d68702802d74f77ea026b5ec52793c791e2da806a3844a46c3"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:70c610f6cbe4b9fce272c407dd9d07e33e6bf7b4aa1b7ffb6f6ded8e634e3592"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win32.whl", hash = "sha256:a401b4598e5d3f4a9a811f3daf42ee2291790c7f9d74b18d75d6e21dda98a1a1"}, + {file = "charset_normalizer-3.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c0b21078a4b56965e2b12f247467b234734491897e99c1d51cee628da9786959"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95eb302ff792e12aba9a8b8f8474ab229a83c103d74a750ec0bd1c1eea32e669"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1a100c6d595a7f316f1b6f01d20815d916e75ff98c27a01ae817439ea7726329"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6339d047dab2780cc6220f46306628e04d9750f02f983ddb37439ca47ced7149"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4b749b9cc6ee664a3300bb3a273c1ca8068c46be705b6c31cf5d276f8628a94"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a38856a971c602f98472050165cea2cdc97709240373041b69030be15047691f"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f87f746ee241d30d6ed93969de31e5ffd09a2961a051e60ae6bddde9ec3583aa"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89f1b185a01fe560bc8ae5f619e924407efca2191b56ce749ec84982fc59a32a"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1c8a2f4c69e08e89632defbfabec2feb8a8d99edc9f89ce33c4b9e36ab63037"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2f4ac36d8e2b4cc1aa71df3dd84ff8efbe3bfb97ac41242fbcfc053c67434f46"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a386ebe437176aab38c041de1260cd3ea459c6ce5263594399880bbc398225b2"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ccd16eb18a849fd8dcb23e23380e2f0a354e8daa0c984b8a732d9cfaba3a776d"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e6a5bf2cba5ae1bb80b154ed68a3cfa2fa00fde979a7f50d6598d3e17d9ac20c"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:45de3f87179c1823e6d9e32156fb14c1927fcc9aba21433f088fdfb555b77c10"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win32.whl", hash = "sha256:1000fba1057b92a65daec275aec30586c3de2401ccdcd41f8a5c1e2c87078706"}, + {file = "charset_normalizer-3.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:8b2c760cfc7042b27ebdb4a43a4453bd829a5742503599144d54a032c5dc7e9e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:855eafa5d5a2034b4621c74925d89c5efef61418570e5ef9b37717d9c796419c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:203f0c8871d5a7987be20c72442488a0b8cfd0f43b7973771640fc593f56321f"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e857a2232ba53ae940d3456f7533ce6ca98b81917d47adc3c7fd55dad8fab858"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e86d77b090dbddbe78867a0275cb4df08ea195e660f1f7f13435a4649e954e5"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4fb39a81950ec280984b3a44f5bd12819953dc5fa3a7e6fa7a80db5ee853952"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2dee8e57f052ef5353cf608e0b4c871aee320dd1b87d351c28764fc0ca55f9f4"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8700f06d0ce6f128de3ccdbc1acaea1ee264d2caa9ca05daaf492fde7c2a7200"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1920d4ff15ce893210c1f0c0e9d19bfbecb7983c76b33f046c13a8ffbd570252"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:c1c76a1743432b4b60ab3358c937a3fe1341c828ae6194108a94c69028247f22"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f7560358a6811e52e9c4d142d497f1a6e10103d3a6881f18d04dbce3729c0e2c"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:c8063cf17b19661471ecbdb3df1c84f24ad2e389e326ccaf89e3fb2484d8dd7e"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:cd6dbe0238f7743d0efe563ab46294f54f9bc8f4b9bcf57c3c666cc5bc9d1299"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:1249cbbf3d3b04902ff081ffbb33ce3377fa6e4c7356f759f3cd076cc138d020"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win32.whl", hash = "sha256:6c409c0deba34f147f77efaa67b8e4bb83d2f11c8806405f76397ae5b8c0d1c9"}, + {file = "charset_normalizer-3.2.0-cp39-cp39-win_amd64.whl", hash = "sha256:7095f6fbfaa55defb6b733cfeb14efaae7a29f0b59d8cf213be4e7ca0b857b80"}, + {file = "charset_normalizer-3.2.0-py3-none-any.whl", hash = "sha256:8e098148dd37b4ce3baca71fb394c81dc5d9c7728c95df695d2dca218edf40e6"}, ] [[package]] name = "click" -version = "8.1.3" +version = "8.1.7" description = "Composable command line interface toolkit" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, - {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, ] [package.dependencies] @@ -225,7 +207,6 @@ importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ @@ -233,11 +214,20 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "colored" +version = "1.4.4" +description = "Simple library for color and formatting to terminal" +optional = false +python-versions = "*" +files = [ + {file = "colored-1.4.4.tar.gz", hash = "sha256:04ff4d4dd514274fe3b99a21bb52fb96f2688c01e93fba7bef37221e7cb56ce0"}, +] + [[package]] name = "cycler" version = "0.11.0" description = "Composable style cycles" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -247,21 +237,19 @@ files = [ [[package]] name = "distlib" -version = "0.3.6" +version = "0.3.7" description = "Distribution utilities" -category = "dev" optional = false python-versions = "*" files = [ - {file = "distlib-0.3.6-py2.py3-none-any.whl", hash = "sha256:f35c4b692542ca110de7ef0bea44d73981caeb34ca0b9b6b2e6d7790dda8f80e"}, - {file = "distlib-0.3.6.tar.gz", hash = "sha256:14bad2d9b04d3a36127ac97f30b12a19268f211063d8f8ee4f47108896e11b46"}, + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, ] [[package]] name = "docutils" version = "0.19" description = "Docutils -- Python Documentation Utilities" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -273,7 +261,6 @@ files = [ name = "docutils-stubs" version = "0.0.22" description = "PEP 561 type stubs for docutils" -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -286,14 +273,13 @@ docutils = ">=0.14" [[package]] name = "exceptiongroup" -version = "1.1.0" +version = "1.1.3" description = "Backport of PEP 654 (exception groups)" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.0-py3-none-any.whl", hash = "sha256:327cbda3da756e2de031a3107b81ab7b3770a602c4d16ca618298c526f4bec1e"}, - {file = "exceptiongroup-1.1.0.tar.gz", hash = "sha256:bcb67d800a4497e1b404c2dd44fca47d3b7a5e5433dbab67f96c1a685cdfdf23"}, + {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, + {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, ] [package.extras] @@ -301,40 +287,37 @@ test = ["pytest (>=6)"] [[package]] name = "execnet" -version = "1.9.0" +version = "2.0.2" description = "execnet: rapid multi-Python deployment" -category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +python-versions = ">=3.7" files = [ - {file = "execnet-1.9.0-py2.py3-none-any.whl", hash = "sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142"}, - {file = "execnet-1.9.0.tar.gz", hash = "sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5"}, + {file = "execnet-2.0.2-py3-none-any.whl", hash = "sha256:88256416ae766bc9e8895c76a87928c0012183da3cc4fc18016e6f050e025f41"}, + {file = "execnet-2.0.2.tar.gz", hash = "sha256:cc59bc4423742fd71ad227122eb0dd44db51efb3dc4095b45ac9a08c770096af"}, ] [package.extras] -testing = ["pre-commit"] +testing = ["hatch", "pre-commit", "pytest", "tox"] [[package]] name = "filelock" -version = "3.9.0" +version = "3.12.2" description = "A platform independent file lock." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.9.0-py3-none-any.whl", hash = "sha256:f58d535af89bb9ad5cd4df046f741f8553a418c01a7856bf0d173bbc9f6bd16d"}, - {file = "filelock-3.9.0.tar.gz", hash = "sha256:7b319f24340b51f55a2bf7a12ac0755a9b03e718311dac567a0f4f7fabd2f5de"}, + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.5)"] -testing = ["covdefaults (>=2.2.2)", "coverage (>=7.0.1)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "fonttools" version = "4.38.0" description = "Tools to manipulate font files" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -358,14 +341,13 @@ woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] [[package]] name = "identify" -version = "2.5.18" +version = "2.5.24" description = "File identification library for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.18-py2.py3-none-any.whl", hash = "sha256:93aac7ecf2f6abf879b8f29a8002d3c6de7086b8c28d88e1ad15045a15ab63f9"}, - {file = "identify-2.5.18.tar.gz", hash = "sha256:89e144fa560cc4cffb6ef2ab5e9fb18ed9f9b3cb054384bab4b95c12f6c309fe"}, + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, ] [package.extras] @@ -375,7 +357,6 @@ license = ["ukkonen"] name = "idna" version = "3.4" description = "Internationalized Domain Names in Applications (IDNA)" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -387,7 +368,6 @@ files = [ name = "imagesize" version = "1.4.1" description = "Getting image size from png/jpeg/jpeg2000/gif file" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" files = [ @@ -397,14 +377,13 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.0.0" +version = "6.7.0" description = "Read metadata from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_metadata-6.0.0-py3-none-any.whl", hash = "sha256:7efb448ec9a5e313a57655d35aa54cd3e01b7e1fbcf72dce1bf06119420f5bad"}, - {file = "importlib_metadata-6.0.0.tar.gz", hash = "sha256:e354bedeb60efa6affdcc8ae121b73544a7aa74156d047311948f6d711cd378d"}, + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, ] [package.dependencies] @@ -414,18 +393,17 @@ zipp = ">=0.5" [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] perf = ["ipython"] -testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] [[package]] name = "importlib-resources" -version = "5.10.2" +version = "5.12.0" description = "Read resources from Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "importlib_resources-5.10.2-py3-none-any.whl", hash = "sha256:7d543798b0beca10b6a01ac7cafda9f822c54db9e8376a6bf57e0cbd74d486b6"}, - {file = "importlib_resources-5.10.2.tar.gz", hash = "sha256:e4a96c8cc0339647ff9a5e0550d9f276fc5a01ffa276012b58ec108cfd7b8484"}, + {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, + {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, ] [package.dependencies] @@ -439,7 +417,6 @@ testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-chec name = "iniconfig" version = "2.0.0" description = "brain-dead simple config-ini parsing" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -451,7 +428,6 @@ files = [ name = "isort" version = "5.11.5" description = "A Python utility / library to sort Python imports." -category = "dev" optional = false python-versions = ">=3.7.0" files = [ @@ -469,7 +445,6 @@ requirements-deprecated-finder = ["pip-api", "pipreqs"] name = "jinja2" version = "3.1.2" description = "A very fast and expressive template engine." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -487,7 +462,6 @@ i18n = ["Babel (>=2.7)"] name = "jsonschema" version = "4.17.3" description = "An implementation of JSON Schema validation for Python" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -509,80 +483,115 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "kiwisolver" -version = "1.4.4" +version = "1.4.5" description = "A fast implementation of the Cassowary constraint solver" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:2f5e60fabb7343a836360c4f0919b8cd0d6dbf08ad2ca6b9cf90bf0c76a3c4f6"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:10ee06759482c78bdb864f4109886dff7b8a56529bc1609d4f1112b93fe6423c"}, - {file = "kiwisolver-1.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c79ebe8f3676a4c6630fd3f777f3cfecf9289666c84e775a67d1d358578dc2e3"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:abbe9fa13da955feb8202e215c4018f4bb57469b1b78c7a4c5c7b93001699938"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7577c1987baa3adc4b3c62c33bd1118c3ef5c8ddef36f0f2c950ae0b199e100d"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ad8285b01b0d4695102546b342b493b3ccc6781fc28c8c6a1bb63e95d22f09"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ed58b8acf29798b036d347791141767ccf65eee7f26bde03a71c944449e53de"}, - {file = "kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a68b62a02953b9841730db7797422f983935aeefceb1679f0fc85cbfbd311c32"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win32.whl", hash = "sha256:e92a513161077b53447160b9bd8f522edfbed4bd9759e4c18ab05d7ef7e49408"}, - {file = "kiwisolver-1.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:3fe20f63c9ecee44560d0e7f116b3a747a5d7203376abeea292ab3152334d004"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ea21f66820452a3f5d1655f8704a60d66ba1191359b96541eaf457710a5fc6"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:bc9db8a3efb3e403e4ecc6cd9489ea2bac94244f80c78e27c31dcc00d2790ac2"}, - {file = "kiwisolver-1.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d5b61785a9ce44e5a4b880272baa7cf6c8f48a5180c3e81c59553ba0cb0821ca"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2dbb44c3f7e6c4d3487b31037b1bdbf424d97687c1747ce4ff2895795c9bf69"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6295ecd49304dcf3bfbfa45d9a081c96509e95f4b9d0eb7ee4ec0530c4a96514"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4bd472dbe5e136f96a4b18f295d159d7f26fd399136f5b17b08c4e5f498cd494"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf7d9fce9bcc4752ca4a1b80aabd38f6d19009ea5cbda0e0856983cf6d0023f5"}, - {file = "kiwisolver-1.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78d6601aed50c74e0ef02f4204da1816147a6d3fbdc8b3872d263338a9052c51"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:877272cf6b4b7e94c9614f9b10140e198d2186363728ed0f701c6eee1baec1da"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:db608a6757adabb32f1cfe6066e39b3706d8c3aa69bbc353a5b61edad36a5cb4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:5853eb494c71e267912275e5586fe281444eb5e722de4e131cddf9d442615626"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:f0a1dbdb5ecbef0d34eb77e56fcb3e95bbd7e50835d9782a45df81cc46949750"}, - {file = "kiwisolver-1.4.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:283dffbf061a4ec60391d51e6155e372a1f7a4f5b15d59c8505339454f8989e4"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win32.whl", hash = "sha256:d06adcfa62a4431d404c31216f0f8ac97397d799cd53800e9d3efc2fbb3cf14e"}, - {file = "kiwisolver-1.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:e7da3fec7408813a7cebc9e4ec55afed2d0fd65c4754bc376bf03498d4e92686"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:62ac9cc684da4cf1778d07a89bf5f81b35834cb96ca523d3a7fb32509380cbf6"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41dae968a94b1ef1897cb322b39360a0812661dba7c682aa45098eb8e193dbdf"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02f79693ec433cb4b5f51694e8477ae83b3205768a6fb48ffba60549080e295b"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d0611a0a2a518464c05ddd5a3a1a0e856ccc10e67079bb17f265ad19ab3c7597"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:db5283d90da4174865d520e7366801a93777201e91e79bacbac6e6927cbceede"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1041feb4cda8708ce73bb4dcb9ce1ccf49d553bf87c3954bdfa46f0c3f77252c"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win32.whl", hash = "sha256:a553dadda40fef6bfa1456dc4be49b113aa92c2a9a9e8711e955618cd69622e3"}, - {file = "kiwisolver-1.4.4-cp37-cp37m-win_amd64.whl", hash = "sha256:03baab2d6b4a54ddbb43bba1a3a2d1627e82d205c5cf8f4c924dc49284b87166"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:841293b17ad704d70c578f1f0013c890e219952169ce8a24ebc063eecf775454"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:f4f270de01dd3e129a72efad823da90cc4d6aafb64c410c9033aba70db9f1ff0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f9f39e2f049db33a908319cf46624a569b36983c7c78318e9726a4cb8923b26c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c97528e64cb9ebeff9701e7938653a9951922f2a38bd847787d4a8e498cc83ae"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d1573129aa0fd901076e2bfb4275a35f5b7aa60fbfb984499d661ec950320b0"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ad881edc7ccb9d65b0224f4e4d05a1e85cf62d73aab798943df6d48ab0cd79a1"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b428ef021242344340460fa4c9185d0b1f66fbdbfecc6c63eff4b7c29fad429d"}, - {file = "kiwisolver-1.4.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:2e407cb4bd5a13984a6c2c0fe1845e4e41e96f183e5e5cd4d77a857d9693494c"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win32.whl", hash = "sha256:75facbe9606748f43428fc91a43edb46c7ff68889b91fa31f53b58894503a191"}, - {file = "kiwisolver-1.4.4-cp38-cp38-win_amd64.whl", hash = "sha256:5bce61af018b0cb2055e0e72e7d65290d822d3feee430b7b8203d8a855e78766"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8c808594c88a025d4e322d5bb549282c93c8e1ba71b790f539567932722d7bd8"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f0a71d85ecdd570ded8ac3d1c0f480842f49a40beb423bb8014539a9f32a5897"}, - {file = "kiwisolver-1.4.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b533558eae785e33e8c148a8d9921692a9fe5aa516efbdff8606e7d87b9d5824"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:efda5fc8cc1c61e4f639b8067d118e742b812c930f708e6667a5ce0d13499e29"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:7c43e1e1206cd421cd92e6b3280d4385d41d7166b3ed577ac20444b6995a445f"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8d3bd6c72b2dd9decf16ce70e20abcb3274ba01b4e1c96031e0c4067d1e7cd"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4ea39b0ccc4f5d803e3337dd46bcce60b702be4d86fd0b3d7531ef10fd99a1ac"}, - {file = "kiwisolver-1.4.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:968f44fdbf6dd757d12920d63b566eeb4d5b395fd2d00d29d7ef00a00582aac9"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win32.whl", hash = "sha256:da7e547706e69e45d95e116e6939488d62174e033b763ab1496b4c29b76fabea"}, - {file = "kiwisolver-1.4.4-cp39-cp39-win_amd64.whl", hash = "sha256:ba59c92039ec0a66103b1d5fe588fa546373587a7d68f5c96f743c3396afc04b"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91672bacaa030f92fc2f43b620d7b337fd9a5af28b0d6ed3f77afc43c4a64b5a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:787518a6789009c159453da4d6b683f468ef7a65bbde796bcea803ccf191058d"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da152d8cdcab0e56e4f45eb08b9aea6455845ec83172092f09b0e077ece2cf7a"}, - {file = "kiwisolver-1.4.4-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ecb1fa0db7bf4cff9dac752abb19505a233c7f16684c5826d1f11ebd9472b871"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:28bc5b299f48150b5f822ce68624e445040595a4ac3d59251703779836eceff9"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:81e38381b782cc7e1e46c4e14cd997ee6040768101aefc8fa3c24a4cc58e98f8"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2a66fdfb34e05b705620dd567f5a03f239a088d5a3f321e7b6ac3239d22aa286"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:872b8ca05c40d309ed13eb2e582cab0c5a05e81e987ab9c521bf05ad1d5cf5cb"}, - {file = "kiwisolver-1.4.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:70e7c2e7b750585569564e2e5ca9845acfaa5da56ac46df68414f29fea97be9f"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:9f85003f5dfa867e86d53fac6f7e6f30c045673fa27b603c397753bebadc3008"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e307eb9bd99801f82789b44bb45e9f541961831c7311521b13a6c85afc09767"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1792d939ec70abe76f5054d3f36ed5656021dcad1322d1cc996d4e54165cef9"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cb459eea32a4e2cf18ba5fcece2dbdf496384413bc1bae15583f19e567f3b2"}, - {file = "kiwisolver-1.4.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:36dafec3d6d6088d34e2de6b85f9d8e2324eb734162fba59d2ba9ed7a2043d5b"}, - {file = "kiwisolver-1.4.4.tar.gz", hash = "sha256:d41997519fcba4a1e46eb4a2fe31bc12f0ff957b2b81bac28db24744f333e955"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, ] [package.dependencies] @@ -590,102 +599,115 @@ typing-extensions = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "lxml" -version = "4.9.2" +version = "4.9.3" description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." -category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" files = [ - {file = "lxml-4.9.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:76cf573e5a365e790396a5cc2b909812633409306c6531a6877c59061e42c4f2"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b1f42b6921d0e81b1bcb5e395bc091a70f41c4d4e55ba99c6da2b31626c44892"}, - {file = "lxml-4.9.2-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:9f102706d0ca011de571de32c3247c6476b55bb6bc65a20f682f000b07a4852a"}, - {file = "lxml-4.9.2-cp27-cp27m-win32.whl", hash = "sha256:8d0b4612b66ff5d62d03bcaa043bb018f74dfea51184e53f067e6fdcba4bd8de"}, - {file = "lxml-4.9.2-cp27-cp27m-win_amd64.whl", hash = "sha256:4c8f293f14abc8fd3e8e01c5bd86e6ed0b6ef71936ded5bf10fe7a5efefbaca3"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2899456259589aa38bfb018c364d6ae7b53c5c22d8e27d0ec7609c2a1ff78b50"}, - {file = "lxml-4.9.2-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6749649eecd6a9871cae297bffa4ee76f90b4504a2a2ab528d9ebe912b101975"}, - {file = "lxml-4.9.2-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:a08cff61517ee26cb56f1e949cca38caabe9ea9fbb4b1e10a805dc39844b7d5c"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:85cabf64adec449132e55616e7ca3e1000ab449d1d0f9d7f83146ed5bdcb6d8a"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8340225bd5e7a701c0fa98284c849c9b9fc9238abf53a0ebd90900f25d39a4e4"}, - {file = "lxml-4.9.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:1ab8f1f932e8f82355e75dda5413a57612c6ea448069d4fb2e217e9a4bed13d4"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:699a9af7dffaf67deeae27b2112aa06b41c370d5e7633e0ee0aea2e0b6c211f7"}, - {file = "lxml-4.9.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b9cc34af337a97d470040f99ba4282f6e6bac88407d021688a5d585e44a23184"}, - {file = "lxml-4.9.2-cp310-cp310-win32.whl", hash = "sha256:d02a5399126a53492415d4906ab0ad0375a5456cc05c3fc0fc4ca11771745cda"}, - {file = "lxml-4.9.2-cp310-cp310-win_amd64.whl", hash = "sha256:a38486985ca49cfa574a507e7a2215c0c780fd1778bb6290c21193b7211702ab"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:c83203addf554215463b59f6399835201999b5e48019dc17f182ed5ad87205c9"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:2a87fa548561d2f4643c99cd13131acb607ddabb70682dcf1dff5f71f781a4bf"}, - {file = "lxml-4.9.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:d6b430a9938a5a5d85fc107d852262ddcd48602c120e3dbb02137c83d212b380"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:3efea981d956a6f7173b4659849f55081867cf897e719f57383698af6f618a92"}, - {file = "lxml-4.9.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:df0623dcf9668ad0445e0558a21211d4e9a149ea8f5666917c8eeec515f0a6d1"}, - {file = "lxml-4.9.2-cp311-cp311-win32.whl", hash = "sha256:da248f93f0418a9e9d94b0080d7ebc407a9a5e6d0b57bb30db9b5cc28de1ad33"}, - {file = "lxml-4.9.2-cp311-cp311-win_amd64.whl", hash = "sha256:3818b8e2c4b5148567e1b09ce739006acfaa44ce3156f8cbbc11062994b8e8dd"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ca989b91cf3a3ba28930a9fc1e9aeafc2a395448641df1f387a2d394638943b0"}, - {file = "lxml-4.9.2-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:822068f85e12a6e292803e112ab876bc03ed1f03dddb80154c395f891ca6b31e"}, - {file = "lxml-4.9.2-cp35-cp35m-win32.whl", hash = "sha256:be7292c55101e22f2a3d4d8913944cbea71eea90792bf914add27454a13905df"}, - {file = "lxml-4.9.2-cp35-cp35m-win_amd64.whl", hash = "sha256:998c7c41910666d2976928c38ea96a70d1aa43be6fe502f21a651e17483a43c5"}, - {file = "lxml-4.9.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:b26a29f0b7fc6f0897f043ca366142d2b609dc60756ee6e4e90b5f762c6adc53"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:ab323679b8b3030000f2be63e22cdeea5b47ee0abd2d6a1dc0c8103ddaa56cd7"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:689bb688a1db722485e4610a503e3e9210dcc20c520b45ac8f7533c837be76fe"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:f49e52d174375a7def9915c9f06ec4e569d235ad428f70751765f48d5926678c"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:36c3c175d34652a35475a73762b545f4527aec044910a651d2bf50de9c3352b1"}, - {file = "lxml-4.9.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a35f8b7fa99f90dd2f5dc5a9fa12332642f087a7641289ca6c40d6e1a2637d8e"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:58bfa3aa19ca4c0f28c5dde0ff56c520fbac6f0daf4fac66ed4c8d2fb7f22e74"}, - {file = "lxml-4.9.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc718cd47b765e790eecb74d044cc8d37d58562f6c314ee9484df26276d36a38"}, - {file = "lxml-4.9.2-cp36-cp36m-win32.whl", hash = "sha256:d5bf6545cd27aaa8a13033ce56354ed9e25ab0e4ac3b5392b763d8d04b08e0c5"}, - {file = "lxml-4.9.2-cp36-cp36m-win_amd64.whl", hash = "sha256:3ab9fa9d6dc2a7f29d7affdf3edebf6ece6fb28a6d80b14c3b2fb9d39b9322c3"}, - {file = "lxml-4.9.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:05ca3f6abf5cf78fe053da9b1166e062ade3fa5d4f92b4ed688127ea7d7b1d03"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:a5da296eb617d18e497bcf0a5c528f5d3b18dadb3619fbdadf4ed2356ef8d941"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:04876580c050a8c5341d706dd464ff04fd597095cc8c023252566a8826505726"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:c9ec3eaf616d67db0764b3bb983962b4f385a1f08304fd30c7283954e6a7869b"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2a29ba94d065945944016b6b74e538bdb1751a1db6ffb80c9d3c2e40d6fa9894"}, - {file = "lxml-4.9.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:a82d05da00a58b8e4c0008edbc8a4b6ec5a4bc1e2ee0fb6ed157cf634ed7fa45"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:223f4232855ade399bd409331e6ca70fb5578efef22cf4069a6090acc0f53c0e"}, - {file = "lxml-4.9.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d17bc7c2ccf49c478c5bdd447594e82692c74222698cfc9b5daae7ae7e90743b"}, - {file = "lxml-4.9.2-cp37-cp37m-win32.whl", hash = "sha256:b64d891da92e232c36976c80ed7ebb383e3f148489796d8d31a5b6a677825efe"}, - {file = "lxml-4.9.2-cp37-cp37m-win_amd64.whl", hash = "sha256:a0a336d6d3e8b234a3aae3c674873d8f0e720b76bc1d9416866c41cd9500ffb9"}, - {file = "lxml-4.9.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:da4dd7c9c50c059aba52b3524f84d7de956f7fef88f0bafcf4ad7dde94a064e8"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:821b7f59b99551c69c85a6039c65b75f5683bdc63270fec660f75da67469ca24"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:e5168986b90a8d1f2f9dc1b841467c74221bd752537b99761a93d2d981e04889"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:8e20cb5a47247e383cf4ff523205060991021233ebd6f924bca927fcf25cf86f"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:13598ecfbd2e86ea7ae45ec28a2a54fb87ee9b9fdb0f6d343297d8e548392c03"}, - {file = "lxml-4.9.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:880bbbcbe2fca64e2f4d8e04db47bcdf504936fa2b33933efd945e1b429bea8c"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7d2278d59425777cfcb19735018d897ca8303abe67cc735f9f97177ceff8027f"}, - {file = "lxml-4.9.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:5344a43228767f53a9df6e5b253f8cdca7dfc7b7aeae52551958192f56d98457"}, - {file = "lxml-4.9.2-cp38-cp38-win32.whl", hash = "sha256:925073b2fe14ab9b87e73f9a5fde6ce6392da430f3004d8b72cc86f746f5163b"}, - {file = "lxml-4.9.2-cp38-cp38-win_amd64.whl", hash = "sha256:9b22c5c66f67ae00c0199f6055705bc3eb3fcb08d03d2ec4059a2b1b25ed48d7"}, - {file = "lxml-4.9.2-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:5f50a1c177e2fa3ee0667a5ab79fdc6b23086bc8b589d90b93b4bd17eb0e64d1"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:090c6543d3696cbe15b4ac6e175e576bcc3f1ccfbba970061b7300b0c15a2140"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:63da2ccc0857c311d764e7d3d90f429c252e83b52d1f8f1d1fe55be26827d1f4"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:5b4545b8a40478183ac06c073e81a5ce4cf01bf1734962577cf2bb569a5b3bbf"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2e430cd2824f05f2d4f687701144556646bae8f249fd60aa1e4c768ba7018947"}, - {file = "lxml-4.9.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6804daeb7ef69e7b36f76caddb85cccd63d0c56dedb47555d2fc969e2af6a1a5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a6e441a86553c310258aca15d1c05903aaf4965b23f3bc2d55f200804e005ee5"}, - {file = "lxml-4.9.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ca34efc80a29351897e18888c71c6aca4a359247c87e0b1c7ada14f0ab0c0fb2"}, - {file = "lxml-4.9.2-cp39-cp39-win32.whl", hash = "sha256:6b418afe5df18233fc6b6093deb82a32895b6bb0b1155c2cdb05203f583053f1"}, - {file = "lxml-4.9.2-cp39-cp39-win_amd64.whl", hash = "sha256:f1496ea22ca2c830cbcbd473de8f114a320da308438ae65abad6bab7867fe38f"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b264171e3143d842ded311b7dccd46ff9ef34247129ff5bf5066123c55c2431c"}, - {file = "lxml-4.9.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:0dc313ef231edf866912e9d8f5a042ddab56c752619e92dfd3a2c277e6a7299a"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-macosx_10_15_x86_64.whl", hash = "sha256:16efd54337136e8cd72fb9485c368d91d77a47ee2d42b057564aae201257d419"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:0f2b1e0d79180f344ff9f321327b005ca043a50ece8713de61d1cb383fb8ac05"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:7b770ed79542ed52c519119473898198761d78beb24b107acf3ad65deae61f1f"}, - {file = "lxml-4.9.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efa29c2fe6b4fdd32e8ef81c1528506895eca86e1d8c4657fda04c9b3786ddf9"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7e91ee82f4199af8c43d8158024cbdff3d931df350252288f0d4ce656df7f3b5"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:b23e19989c355ca854276178a0463951a653309fb8e57ce674497f2d9f208746"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:01d36c05f4afb8f7c20fd9ed5badca32a2029b93b1750f571ccc0b142531caf7"}, - {file = "lxml-4.9.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7b515674acfdcadb0eb5d00d8a709868173acece5cb0be3dd165950cbfdf5409"}, - {file = "lxml-4.9.2.tar.gz", hash = "sha256:2455cfaeb7ac70338b3257f41e21f0724f4b5b0c0e7702da67ee6c3640835b67"}, + {file = "lxml-4.9.3-cp27-cp27m-macosx_11_0_x86_64.whl", hash = "sha256:b0a545b46b526d418eb91754565ba5b63b1c0b12f9bd2f808c852d9b4b2f9b5c"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:075b731ddd9e7f68ad24c635374211376aa05a281673ede86cbe1d1b3455279d"}, + {file = "lxml-4.9.3-cp27-cp27m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1e224d5755dba2f4a9498e150c43792392ac9b5380aa1b845f98a1618c94eeef"}, + {file = "lxml-4.9.3-cp27-cp27m-win32.whl", hash = "sha256:2c74524e179f2ad6d2a4f7caf70e2d96639c0954c943ad601a9e146c76408ed7"}, + {file = "lxml-4.9.3-cp27-cp27m-win_amd64.whl", hash = "sha256:4f1026bc732b6a7f96369f7bfe1a4f2290fb34dce00d8644bc3036fb351a4ca1"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c0781a98ff5e6586926293e59480b64ddd46282953203c76ae15dbbbf302e8bb"}, + {file = "lxml-4.9.3-cp27-cp27mu-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:cef2502e7e8a96fe5ad686d60b49e1ab03e438bd9123987994528febd569868e"}, + {file = "lxml-4.9.3-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:b86164d2cff4d3aaa1f04a14685cbc072efd0b4f99ca5708b2ad1b9b5988a991"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:42871176e7896d5d45138f6d28751053c711ed4d48d8e30b498da155af39aebd"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:ae8b9c6deb1e634ba4f1930eb67ef6e6bf6a44b6eb5ad605642b2d6d5ed9ce3c"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:411007c0d88188d9f621b11d252cce90c4a2d1a49db6c068e3c16422f306eab8"}, + {file = "lxml-4.9.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:cd47b4a0d41d2afa3e58e5bf1f62069255aa2fd6ff5ee41604418ca925911d76"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0e2cb47860da1f7e9a5256254b74ae331687b9672dfa780eed355c4c9c3dbd23"}, + {file = "lxml-4.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1247694b26342a7bf47c02e513d32225ededd18045264d40758abeb3c838a51f"}, + {file = "lxml-4.9.3-cp310-cp310-win32.whl", hash = "sha256:cdb650fc86227eba20de1a29d4b2c1bfe139dc75a0669270033cb2ea3d391b85"}, + {file = "lxml-4.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:97047f0d25cd4bcae81f9ec9dc290ca3e15927c192df17331b53bebe0e3ff96d"}, + {file = "lxml-4.9.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:1f447ea5429b54f9582d4b955f5f1985f278ce5cf169f72eea8afd9502973dd5"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:57d6ba0ca2b0c462f339640d22882acc711de224d769edf29962b09f77129cbf"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:9767e79108424fb6c3edf8f81e6730666a50feb01a328f4a016464a5893f835a"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:71c52db65e4b56b8ddc5bb89fb2e66c558ed9d1a74a45ceb7dcb20c191c3df2f"}, + {file = "lxml-4.9.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:d73d8ecf8ecf10a3bd007f2192725a34bd62898e8da27eb9d32a58084f93962b"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0a3d3487f07c1d7f150894c238299934a2a074ef590b583103a45002035be120"}, + {file = "lxml-4.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:9e28c51fa0ce5674be9f560c6761c1b441631901993f76700b1b30ca6c8378d6"}, + {file = "lxml-4.9.3-cp311-cp311-win32.whl", hash = "sha256:0bfd0767c5c1de2551a120673b72e5d4b628737cb05414f03c3277bf9bed3305"}, + {file = "lxml-4.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:25f32acefac14ef7bd53e4218fe93b804ef6f6b92ffdb4322bb6d49d94cad2bc"}, + {file = "lxml-4.9.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:d3ff32724f98fbbbfa9f49d82852b159e9784d6094983d9a8b7f2ddaebb063d4"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:48d6ed886b343d11493129e019da91d4039826794a3e3027321c56d9e71505be"}, + {file = "lxml-4.9.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:9a92d3faef50658dd2c5470af249985782bf754c4e18e15afb67d3ab06233f13"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b4e4bc18382088514ebde9328da057775055940a1f2e18f6ad2d78aa0f3ec5b9"}, + {file = "lxml-4.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fc9b106a1bf918db68619fdcd6d5ad4f972fdd19c01d19bdb6bf63f3589a9ec5"}, + {file = "lxml-4.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:d37017287a7adb6ab77e1c5bee9bcf9660f90ff445042b790402a654d2ad81d8"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56dc1f1ebccc656d1b3ed288f11e27172a01503fc016bcabdcbc0978b19352b7"}, + {file = "lxml-4.9.3-cp35-cp35m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:578695735c5a3f51569810dfebd05dd6f888147a34f0f98d4bb27e92b76e05c2"}, + {file = "lxml-4.9.3-cp35-cp35m-win32.whl", hash = "sha256:704f61ba8c1283c71b16135caf697557f5ecf3e74d9e453233e4771d68a1f42d"}, + {file = "lxml-4.9.3-cp35-cp35m-win_amd64.whl", hash = "sha256:c41bfca0bd3532d53d16fd34d20806d5c2b1ace22a2f2e4c0008570bf2c58833"}, + {file = "lxml-4.9.3-cp36-cp36m-macosx_11_0_x86_64.whl", hash = "sha256:64f479d719dc9f4c813ad9bb6b28f8390360660b73b2e4beb4cb0ae7104f1c12"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:dd708cf4ee4408cf46a48b108fb9427bfa00b9b85812a9262b5c668af2533ea5"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5c31c7462abdf8f2ac0577d9f05279727e698f97ecbb02f17939ea99ae8daa98"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e3cd95e10c2610c360154afdc2f1480aea394f4a4f1ea0a5eacce49640c9b190"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_28_x86_64.whl", hash = "sha256:4930be26af26ac545c3dffb662521d4e6268352866956672231887d18f0eaab2"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4aec80cde9197340bc353d2768e2a75f5f60bacda2bab72ab1dc499589b3878c"}, + {file = "lxml-4.9.3-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:14e019fd83b831b2e61baed40cab76222139926b1fb5ed0e79225bc0cae14584"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0c0850c8b02c298d3c7006b23e98249515ac57430e16a166873fc47a5d549287"}, + {file = "lxml-4.9.3-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:aca086dc5f9ef98c512bac8efea4483eb84abbf926eaeedf7b91479feb092458"}, + {file = "lxml-4.9.3-cp36-cp36m-win32.whl", hash = "sha256:50baa9c1c47efcaef189f31e3d00d697c6d4afda5c3cde0302d063492ff9b477"}, + {file = "lxml-4.9.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bef4e656f7d98aaa3486d2627e7d2df1157d7e88e7efd43a65aa5dd4714916cf"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:46f409a2d60f634fe550f7133ed30ad5321ae2e6630f13657fb9479506b00601"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:4c28a9144688aef80d6ea666c809b4b0e50010a2aca784c97f5e6bf143d9f129"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:141f1d1a9b663c679dc524af3ea1773e618907e96075262726c7612c02b149a4"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:53ace1c1fd5a74ef662f844a0413446c0629d151055340e9893da958a374f70d"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:17a753023436a18e27dd7769e798ce302963c236bc4114ceee5b25c18c52c693"}, + {file = "lxml-4.9.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:7d298a1bd60c067ea75d9f684f5f3992c9d6766fadbc0bcedd39750bf344c2f4"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:081d32421db5df44c41b7f08a334a090a545c54ba977e47fd7cc2deece78809a"}, + {file = "lxml-4.9.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:23eed6d7b1a3336ad92d8e39d4bfe09073c31bfe502f20ca5116b2a334f8ec02"}, + {file = "lxml-4.9.3-cp37-cp37m-win32.whl", hash = "sha256:1509dd12b773c02acd154582088820893109f6ca27ef7291b003d0e81666109f"}, + {file = "lxml-4.9.3-cp37-cp37m-win_amd64.whl", hash = "sha256:120fa9349a24c7043854c53cae8cec227e1f79195a7493e09e0c12e29f918e52"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4d2d1edbca80b510443f51afd8496be95529db04a509bc8faee49c7b0fb6d2cc"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:8d7e43bd40f65f7d97ad8ef5c9b1778943d02f04febef12def25f7583d19baac"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:71d66ee82e7417828af6ecd7db817913cb0cf9d4e61aa0ac1fde0583d84358db"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:6fc3c450eaa0b56f815c7b62f2b7fba7266c4779adcf1cece9e6deb1de7305ce"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:65299ea57d82fb91c7f019300d24050c4ddeb7c5a190e076b5f48a2b43d19c42"}, + {file = "lxml-4.9.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:eadfbbbfb41b44034a4c757fd5d70baccd43296fb894dba0295606a7cf3124aa"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3e9bdd30efde2b9ccfa9cb5768ba04fe71b018a25ea093379c857c9dad262c40"}, + {file = "lxml-4.9.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fcdd00edfd0a3001e0181eab3e63bd5c74ad3e67152c84f93f13769a40e073a7"}, + {file = "lxml-4.9.3-cp38-cp38-win32.whl", hash = "sha256:57aba1bbdf450b726d58b2aea5fe47c7875f5afb2c4a23784ed78f19a0462574"}, + {file = "lxml-4.9.3-cp38-cp38-win_amd64.whl", hash = "sha256:92af161ecbdb2883c4593d5ed4815ea71b31fafd7fd05789b23100d081ecac96"}, + {file = "lxml-4.9.3-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:9bb6ad405121241e99a86efff22d3ef469024ce22875a7ae045896ad23ba2340"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8ed74706b26ad100433da4b9d807eae371efaa266ffc3e9191ea436087a9d6a7"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:fbf521479bcac1e25a663df882c46a641a9bff6b56dc8b0fafaebd2f66fb231b"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:303bf1edce6ced16bf67a18a1cf8339d0db79577eec5d9a6d4a80f0fb10aa2da"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:5515edd2a6d1a5a70bfcdee23b42ec33425e405c5b351478ab7dc9347228f96e"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:690dafd0b187ed38583a648076865d8c229661ed20e48f2335d68e2cf7dc829d"}, + {file = "lxml-4.9.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:b6420a005548ad52154c8ceab4a1290ff78d757f9e5cbc68f8c77089acd3c432"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bb3bb49c7a6ad9d981d734ef7c7193bc349ac338776a0360cc671eaee89bcf69"}, + {file = "lxml-4.9.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d27be7405547d1f958b60837dc4c1007da90b8b23f54ba1f8b728c78fdb19d50"}, + {file = "lxml-4.9.3-cp39-cp39-win32.whl", hash = "sha256:8df133a2ea5e74eef5e8fc6f19b9e085f758768a16e9877a60aec455ed2609b2"}, + {file = "lxml-4.9.3-cp39-cp39-win_amd64.whl", hash = "sha256:4dd9a263e845a72eacb60d12401e37c616438ea2e5442885f65082c276dfb2b2"}, + {file = "lxml-4.9.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:6689a3d7fd13dc687e9102a27e98ef33730ac4fe37795d5036d18b4d527abd35"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:f6bdac493b949141b733c5345b6ba8f87a226029cbabc7e9e121a413e49441e0"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:05186a0f1346ae12553d66df1cfce6f251589fea3ad3da4f3ef4e34b2d58c6a3"}, + {file = "lxml-4.9.3-pp37-pypy37_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c2006f5c8d28dee289f7020f721354362fa304acbaaf9745751ac4006650254b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:5c245b783db29c4e4fbbbfc9c5a78be496c9fea25517f90606aa1f6b2b3d5f7b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:4fb960a632a49f2f089d522f70496640fdf1218f1243889da3822e0a9f5f3ba7"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:50670615eaf97227d5dc60de2dc99fb134a7130d310d783314e7724bf163f75d"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:9719fe17307a9e814580af1f5c6e05ca593b12fb7e44fe62450a5384dbf61b4b"}, + {file = "lxml-4.9.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3331bece23c9ee066e0fb3f96c61322b9e0f54d775fccefff4c38ca488de283a"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:ed667f49b11360951e201453fc3967344d0d0263aa415e1619e85ae7fd17b4e0"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_24_i686.whl", hash = "sha256:8b77946fd508cbf0fccd8e400a7f71d4ac0e1595812e66025bac475a8e811694"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:e4da8ca0c0c0aea88fd46be8e44bd49716772358d648cce45fe387f7b92374a7"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fe4bda6bd4340caa6e5cf95e73f8fea5c4bfc55763dd42f1b50a94c1b4a2fbd4"}, + {file = "lxml-4.9.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f3df3db1d336b9356dd3112eae5f5c2b8b377f3bc826848567f10bfddfee77e9"}, + {file = "lxml-4.9.3.tar.gz", hash = "sha256:48628bd53a426c9eb9bc066a923acaa0878d1e86129fd5359aee99285f4eed9c"}, ] [package.extras] cssselect = ["cssselect (>=0.7)"] html5 = ["html5lib"] htmlsoup = ["BeautifulSoup4"] -source = ["Cython (>=0.29.7)"] +source = ["Cython (>=0.29.35)"] [[package]] name = "markdown-it-py" version = "2.2.0" description = "Python port of markdown-it. Markdown parsing, done right!" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -709,69 +731,67 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.2" +version = "2.1.3" description = "Safely add untrusted strings to HTML/XML markup." -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:665a36ae6f8f20a4676b53224e33d456a6f5a72657d9c83c2aa00765072f31f7"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:340bea174e9761308703ae988e982005aedf427de816d1afe98147668cc03036"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22152d00bf4a9c7c83960521fc558f55a1adbc0631fbb00a9471e097b19d72e1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28057e985dace2f478e042eaa15606c7efccb700797660629da387eb289b9323"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca244fa73f50a800cf8c3ebf7fd93149ec37f5cb9596aa8873ae2c1d23498601"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9d971ec1e79906046aa3ca266de79eac42f1dbf3612a05dc9368125952bd1a1"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:7e007132af78ea9df29495dbf7b5824cb71648d7133cf7848a2a5dd00d36f9ff"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7313ce6a199651c4ed9d7e4cfb4aa56fe923b1adf9af3b420ee14e6d9a73df65"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win32.whl", hash = "sha256:c4a549890a45f57f1ebf99c067a4ad0cb423a05544accaf2b065246827ed9603"}, - {file = "MarkupSafe-2.1.2-cp310-cp310-win_amd64.whl", hash = "sha256:835fb5e38fd89328e9c81067fd642b3593c33e1e17e2fdbf77f5676abb14a156"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2ec4f2d48ae59bbb9d1f9d7efb9236ab81429a764dedca114f5fdabbc3788013"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:608e7073dfa9e38a85d38474c082d4281f4ce276ac0010224eaba11e929dd53a"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:65608c35bfb8a76763f37036547f7adfd09270fbdbf96608be2bead319728fcd"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2bfb563d0211ce16b63c7cb9395d2c682a23187f54c3d79bfec33e6705473c6"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:da25303d91526aac3672ee6d49a2f3db2d9502a4a60b55519feb1a4c7714e07d"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:9cad97ab29dfc3f0249b483412c85c8ef4766d96cdf9dcf5a1e3caa3f3661cf1"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:085fd3201e7b12809f9e6e9bc1e5c96a368c8523fad5afb02afe3c051ae4afcc"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1bea30e9bf331f3fef67e0a3877b2288593c98a21ccb2cf29b74c581a4eb3af0"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win32.whl", hash = "sha256:7df70907e00c970c60b9ef2938d894a9381f38e6b9db73c5be35e59d92e06625"}, - {file = "MarkupSafe-2.1.2-cp311-cp311-win_amd64.whl", hash = "sha256:e55e40ff0cc8cc5c07996915ad367fa47da6b3fc091fdadca7f5403239c5fec3"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a6e40afa7f45939ca356f348c8e23048e02cb109ced1eb8420961b2f40fb373a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf877ab4ed6e302ec1d04952ca358b381a882fbd9d1b07cccbfd61783561f98a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63ba06c9941e46fa389d389644e2d8225e0e3e5ebcc4ff1ea8506dce646f8c8a"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1cd098434e83e656abf198f103a8207a8187c0fc110306691a2e94a78d0abb2"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:55f44b440d491028addb3b88f72207d71eeebfb7b5dbf0643f7c023ae1fba619"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:a6f2fcca746e8d5910e18782f976489939d54a91f9411c32051b4aab2bd7c513"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:0b462104ba25f1ac006fdab8b6a01ebbfbce9ed37fd37fd4acd70c67c973e460"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win32.whl", hash = "sha256:7668b52e102d0ed87cb082380a7e2e1e78737ddecdde129acadb0eccc5423859"}, - {file = "MarkupSafe-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6d6607f98fcf17e534162f0709aaad3ab7a96032723d8ac8750ffe17ae5a0666"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:a806db027852538d2ad7555b203300173dd1b77ba116de92da9afbc3a3be3eed"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:a4abaec6ca3ad8660690236d11bfe28dfd707778e2442b45addd2f086d6ef094"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f03a532d7dee1bed20bc4884194a16160a2de9ffc6354b3878ec9682bb623c54"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4cf06cdc1dda95223e9d2d3c58d3b178aa5dacb35ee7e3bbac10e4e1faacb419"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22731d79ed2eb25059ae3df1dfc9cb1546691cc41f4e3130fe6bfbc3ecbbecfa"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:f8ffb705ffcf5ddd0e80b65ddf7bed7ee4f5a441ea7d3419e861a12eaf41af58"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8db032bf0ce9022a8e41a22598eefc802314e81b879ae093f36ce9ddf39ab1ba"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:2298c859cfc5463f1b64bd55cb3e602528db6fa0f3cfd568d3605c50678f8f03"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win32.whl", hash = "sha256:50c42830a633fa0cf9e7d27664637532791bfc31c731a87b202d2d8ac40c3ea2"}, - {file = "MarkupSafe-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:bb06feb762bade6bf3c8b844462274db0c76acc95c52abe8dbed28ae3d44a147"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:99625a92da8229df6d44335e6fcc558a5037dd0a760e11d84be2260e6f37002f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8bca7e26c1dd751236cfb0c6c72d4ad61d986e9a41bbf76cb445f69488b2a2bd"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40627dcf047dadb22cd25ea7ecfe9cbf3bbbad0482ee5920b582f3809c97654f"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40dfd3fefbef579ee058f139733ac336312663c6706d1163b82b3003fb1925c4"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:090376d812fb6ac5f171e5938e82e7f2d7adc2b629101cec0db8b267815c85e2"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2e7821bffe00aa6bd07a23913b7f4e01328c3d5cc0b40b36c0bd81d362faeb65"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:c0a33bc9f02c2b17c3ea382f91b4db0e6cde90b63b296422a939886a7a80de1c"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b8526c6d437855442cdd3d87eede9c425c4445ea011ca38d937db299382e6fa3"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win32.whl", hash = "sha256:137678c63c977754abe9086a3ec011e8fd985ab90631145dfb9294ad09c102a7"}, - {file = "MarkupSafe-2.1.2-cp39-cp39-win_amd64.whl", hash = "sha256:0576fe974b40a400449768941d5d0858cc624e3249dfd1e0c33674e5c7ca7aed"}, - {file = "MarkupSafe-2.1.2.tar.gz", hash = "sha256:abcabc8c2b26036d62d4c746381a6f7cf60aafcc653198ad678306986b09450d"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, + {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, + {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, ] [[package]] name = "matplotlib" version = "3.5.3" description = "Python plotting package" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -826,7 +846,6 @@ python-dateutil = ">=2.7" name = "mdurl" version = "0.1.2" description = "Markdown URL utilities" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -836,50 +855,58 @@ files = [ [[package]] name = "memray" -version = "1.6.0" +version = "1.9.1" description = "A memory profiler for Python applications" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "memray-1.6.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:5de6ab0660c97c50c27333a6e4d7c41cf6ef43d8d17b173b7abd109800a9e235"}, - {file = "memray-1.6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2003a78b4f2725f69cf2f6d9fd7c81006639803d8904b6c4a089a3f48de6f1aa"}, - {file = "memray-1.6.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d7547349cf56decff0686f87b766a1d81784b0b86b2a1013b12ee5c1236e2b41"}, - {file = "memray-1.6.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e96cb195736ae8f16879c976849b1af01bb667bfdcead49598bf54b09e7f4e18"}, - {file = "memray-1.6.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:3436c58ad132c8cf060a55cd7428fa13924a40c1cb22dfaaf2a9d68e06969289"}, - {file = "memray-1.6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4193b5109cb2ef057cedf4615277096050fc04efd02ac6628a08391e1b4b6d53"}, - {file = "memray-1.6.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:60e6c50861ade399ee26756c651e7f5f1105b3f1a64f63d6a0495edcc34d5242"}, - {file = "memray-1.6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:232c9b7c64b57000c40cb859b9bd987f04044fb0758d255c3e7282f9c4bc28b0"}, - {file = "memray-1.6.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:32d8bf124c9e16f8eeefc00e0afae480e1a9a5ed8e194d23f075af5fcbb55348"}, - {file = "memray-1.6.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:790b4c559765be716c1e4e073f547e7fc3b38e2fb23f43d24684cb2041e61cb4"}, - {file = "memray-1.6.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:532b81e80d112a2035ef00e35774cc0f4a701c6fbd2955f546bbf10340d38627"}, - {file = "memray-1.6.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:63f96a94392e2bb80a1d3d0a10dcb9d6bbc697340d566a66717bffbf42f28310"}, - {file = "memray-1.6.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:91e1d709771bd1b598dedf114cbcd128a06252a2da2192eb5270304264db62e8"}, - {file = "memray-1.6.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:71dec332f2fdbfa550e15dbf82a7df2699a303a24a6da52d21ab1f3edec59bd1"}, - {file = "memray-1.6.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:8673f7d90603f4b3b3e96f3a2f9943776c123867b00b161433c751beaf3a155f"}, - {file = "memray-1.6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:052fc4f47956b10f91b087543c2aafb858605d70b89907e439bf4949af9e6c37"}, - {file = "memray-1.6.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09f89ea9a61f965d51abdc76dee6929eccfba5e2dd21f6ddfd45ec23d3e4b6cb"}, - {file = "memray-1.6.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:21c17bae6969c58bdbe266b84cefb76992af1c79597c6af5ee147dcc742d7772"}, - {file = "memray-1.6.0.tar.gz", hash = "sha256:e22ad913c46f7402c1eb0ac0b3e61cac43f4f1411fb987da492a71403317e45f"}, + {file = "memray-1.9.1-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:aae3c2b79b4814183ce60e1b6abedc5f56969dcab3f0a8f00d91f9964ae72727"}, + {file = "memray-1.9.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:152d4b6b501a83a4cdafe5bd757a0940ebc5ac2b2b091f6f7c306ac9a8209da5"}, + {file = "memray-1.9.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:bf96d09c7c160ce2c05fa3a077da2563b299985e0542833b70f8b19350df5df8"}, + {file = "memray-1.9.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3837aed792d90e90743448feae98c3a8a3b4da389aab49c359c9014dfdb8bff9"}, + {file = "memray-1.9.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a773c0e0a28be72e4df8dbb00cfc0cff40f992fa413e078b861bf0740910c958"}, + {file = "memray-1.9.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:939270ede80b6c2e0e56dd75edb6a97b44a80bad977c81c68f32fdb3200ff2d5"}, + {file = "memray-1.9.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1fad0e170264f6f71b7ed83843f896a7a9a4efe5684aa40fe48892dc546c5017"}, + {file = "memray-1.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7af9677277d62b1c59ce8e3d493a9f95f1eea1cb6ac362de1b1faad7bfbb18de"}, + {file = "memray-1.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6512866eb49cea99fd0915d8c86d21cad4bf40050092a986e32c2c8c4d6e0d8f"}, + {file = "memray-1.9.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b3c634dac856f5e5d899a944509116f53c36638559f43dda6255333068274b8"}, + {file = "memray-1.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b80f09e178edbc0de6d41d55592ec209936cccb611638b3e7da2c45693433e2b"}, + {file = "memray-1.9.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c602969b1e6dc9502a6911b721536a0209423e798b6cdc690fa0f5b8de02653c"}, + {file = "memray-1.9.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c2a0a4b6d48f7a6ac18ba475a1deaba3f1c237ee37547a34680ee449c393aacc"}, + {file = "memray-1.9.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a47a39af7ea6960a54a80069bc912b6879046f6e8310d46d6286568c76aea50a"}, + {file = "memray-1.9.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3aed29f34bac1a1a6b5ea47700123b3fc2cee2c9c21fe7bc245edcf704d556fd"}, + {file = "memray-1.9.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:16dcd1ddb01826dbbacc91fd6b3b01791263e60bde91901d60e48364480aa127"}, + {file = "memray-1.9.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:caec236f873b097eeacc192d20f6fc0490988f37176ea27f0bdf697331353b3b"}, + {file = "memray-1.9.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:facfee26da17dfcfbb0b62ff2b7041169ad6017c9747e762d7a7e17725e55124"}, + {file = "memray-1.9.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f647168ee77af4c447ff73e2584a2e3f3d8e13655aa6c0d33f02fa19947d5cc3"}, + {file = "memray-1.9.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9ac8f6e249395b24b7f7773b791e9686557216f5f12c4cbe97d0e0c8b0494d7e"}, + {file = "memray-1.9.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a3ce139c103435c3e366ea515d4081a3144a48cf3aae4a5c7bcf2ca7bd35285"}, + {file = "memray-1.9.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3015a28fe6e8cf1d0cd741085da58cc0091ed895161ecacc6a159c14af7a5a35"}, + {file = "memray-1.9.1-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:0e9532a9046554fa1b5166c4a02c54d35775e745a0a895e33c5b3ce6288116d3"}, + {file = "memray-1.9.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c37d2d34b0426051f98597a3732167e3f82e9d37251a1cd73c23b7384e4f842c"}, + {file = "memray-1.9.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f81dede3d702f4d2030f7985caad145f5ff7f33eddc31b09caa49b42071ba275"}, + {file = "memray-1.9.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:aab379c26255bdb4e1d455620f8b8ace1c4e9a91f51de176bfcf9b09e357a7ea"}, + {file = "memray-1.9.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:320ff2aca8e12001563a5895f40349a1a16751e56c168e84f8f76274e591cf42"}, + {file = "memray-1.9.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a8a56e6bc88037c99e899697f312540171042e097e5d2f5688fccaa6bc9008d4"}, + {file = "memray-1.9.1.tar.gz", hash = "sha256:d676ae40ef8ae9c41bf3a27f5fa89c1e9f80d9ba8e9f7e1e7073b5f90b3f265b"}, ] [package.dependencies] -jinja2 = "*" +jinja2 = ">=2.9" rich = ">=11.2.0" typing-extensions = {version = "*", markers = "python_version < \"3.8.0\""} [package.extras] benchmark = ["asv"] -dev = ["Cython", "asv", "black", "bump2version", "check-manifest", "flake8", "furo", "greenlet", "ipython", "isort", "mypy", "pytest", "pytest-cov", "sphinx", "sphinx-argparse", "towncrier"] +dev = ["Cython", "IPython", "asv", "black", "bump2version", "check-manifest", "flake8", "furo", "greenlet", "ipython", "isort", "mypy", "pytest", "pytest-cov", "setuptools", "sphinx", "sphinx-argparse", "towncrier"] docs = ["IPython", "bump2version", "furo", "sphinx", "sphinx-argparse", "towncrier"] lint = ["black", "check-manifest", "flake8", "isort", "mypy"] -test = ["Cython", "greenlet", "ipython", "pytest", "pytest-cov"] +test = ["Cython", "greenlet", "ipython", "pytest", "pytest-cov", "setuptools"] [[package]] name = "mypy" version = "0.991" description = "Optional static typing for Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -931,7 +958,6 @@ reports = ["lxml"] name = "mypy-extensions" version = "1.0.0" description = "Type system extensions for programs checked with the mypy type checker." -category = "dev" optional = false python-versions = ">=3.5" files = [ @@ -941,14 +967,13 @@ files = [ [[package]] name = "nodeenv" -version = "1.7.0" +version = "1.8.0" description = "Node.js virtual environment builder" -category = "dev" optional = false python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" files = [ - {file = "nodeenv-1.7.0-py2.py3-none-any.whl", hash = "sha256:27083a7b96a25f2f5e1d8cb4b6317ee8aeda3bdd121394e5ac54e498028a042e"}, - {file = "nodeenv-1.7.0.tar.gz", hash = "sha256:e0e7f7dfb85fc5394c6fe1e8fa98131a2473e04311a45afb6508f7cf1836fa2b"}, + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, ] [package.dependencies] @@ -958,7 +983,6 @@ setuptools = "*" name = "numpy" version = "1.21.1" description = "NumPy is the fundamental package for array computing with Python." -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -994,124 +1018,109 @@ files = [ [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] name = "pathspec" -version = "0.11.0" +version = "0.11.2" description = "Utility library for gitignore style pattern matching of file paths." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pathspec-0.11.0-py3-none-any.whl", hash = "sha256:3a66eb970cbac598f9e5ccb5b2cf58930cd8e3ed86d393d541eaf2d8b1705229"}, - {file = "pathspec-0.11.0.tar.gz", hash = "sha256:64d338d4e0914e91c1792321e6907b5a593f1ab1851de7fc269557a21b30ebbc"}, + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, ] [[package]] name = "pillow" -version = "9.4.0" +version = "9.5.0" description = "Python Imaging Library (Fork)" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "Pillow-9.4.0-1-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b4b4e9dda4f4e4c4e6896f93e84a8f0bcca3b059de9ddf67dac3c334b1195e1"}, - {file = "Pillow-9.4.0-1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:fb5c1ad6bad98c57482236a21bf985ab0ef42bd51f7ad4e4538e89a997624e12"}, - {file = "Pillow-9.4.0-1-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:f0caf4a5dcf610d96c3bd32932bfac8aee61c96e60481c2a0ea58da435e25acd"}, - {file = "Pillow-9.4.0-1-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:3f4cc516e0b264c8d4ccd6b6cbc69a07c6d582d8337df79be1e15a5056b258c9"}, - {file = "Pillow-9.4.0-1-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:b8c2f6eb0df979ee99433d8b3f6d193d9590f735cf12274c108bd954e30ca858"}, - {file = "Pillow-9.4.0-1-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b70756ec9417c34e097f987b4d8c510975216ad26ba6e57ccb53bc758f490dab"}, - {file = "Pillow-9.4.0-1-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:43521ce2c4b865d385e78579a082b6ad1166ebed2b1a2293c3be1d68dd7ca3b9"}, - {file = "Pillow-9.4.0-2-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:9d9a62576b68cd90f7075876f4e8444487db5eeea0e4df3ba298ee38a8d067b0"}, - {file = "Pillow-9.4.0-2-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:87708d78a14d56a990fbf4f9cb350b7d89ee8988705e58e39bdf4d82c149210f"}, - {file = "Pillow-9.4.0-2-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:8a2b5874d17e72dfb80d917213abd55d7e1ed2479f38f001f264f7ce7bae757c"}, - {file = "Pillow-9.4.0-2-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:83125753a60cfc8c412de5896d10a0a405e0bd88d0470ad82e0869ddf0cb3848"}, - {file = "Pillow-9.4.0-2-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:9e5f94742033898bfe84c93c831a6f552bb629448d4072dd312306bab3bd96f1"}, - {file = "Pillow-9.4.0-2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:013016af6b3a12a2f40b704677f8b51f72cb007dac785a9933d5c86a72a7fe33"}, - {file = "Pillow-9.4.0-2-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:99d92d148dd03fd19d16175b6d355cc1b01faf80dae93c6c3eb4163709edc0a9"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157"}, - {file = "Pillow-9.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5"}, - {file = "Pillow-9.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28"}, - {file = "Pillow-9.4.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35"}, - {file = "Pillow-9.4.0-cp310-cp310-win32.whl", hash = "sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a"}, - {file = "Pillow-9.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133"}, - {file = "Pillow-9.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4"}, - {file = "Pillow-9.4.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8"}, - {file = "Pillow-9.4.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"}, - {file = "Pillow-9.4.0-cp311-cp311-win32.whl", hash = "sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c"}, - {file = "Pillow-9.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee"}, - {file = "Pillow-9.4.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4"}, - {file = "Pillow-9.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5"}, - {file = "Pillow-9.4.0-cp37-cp37m-win32.whl", hash = "sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e"}, - {file = "Pillow-9.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9"}, - {file = "Pillow-9.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d"}, - {file = "Pillow-9.4.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f"}, - {file = "Pillow-9.4.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628"}, - {file = "Pillow-9.4.0-cp38-cp38-win32.whl", hash = "sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d"}, - {file = "Pillow-9.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569"}, - {file = "Pillow-9.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503"}, - {file = "Pillow-9.4.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2"}, - {file = "Pillow-9.4.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153"}, - {file = "Pillow-9.4.0-cp39-cp39-win32.whl", hash = "sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c"}, - {file = "Pillow-9.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df"}, - {file = "Pillow-9.4.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a"}, - {file = "Pillow-9.4.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9"}, - {file = "Pillow-9.4.0.tar.gz", hash = "sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e"}, + {file = "Pillow-9.5.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:ace6ca218308447b9077c14ea4ef381ba0b67ee78d64046b3f19cf4e1139ad16"}, + {file = "Pillow-9.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d3d403753c9d5adc04d4694d35cf0391f0f3d57c8e0030aac09d7678fa8030aa"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ba1b81ee69573fe7124881762bb4cd2e4b6ed9dd28c9c60a632902fe8db8b38"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe7e1c262d3392afcf5071df9afa574544f28eac825284596ac6db56e6d11062"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f36397bf3f7d7c6a3abdea815ecf6fd14e7fcd4418ab24bae01008d8d8ca15e"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:252a03f1bdddce077eff2354c3861bf437c892fb1832f75ce813ee94347aa9b5"}, + {file = "Pillow-9.5.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:85ec677246533e27770b0de5cf0f9d6e4ec0c212a1f89dfc941b64b21226009d"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b416f03d37d27290cb93597335a2f85ed446731200705b22bb927405320de903"}, + {file = "Pillow-9.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1781a624c229cb35a2ac31cc4a77e28cafc8900733a864870c49bfeedacd106a"}, + {file = "Pillow-9.5.0-cp310-cp310-win32.whl", hash = "sha256:8507eda3cd0608a1f94f58c64817e83ec12fa93a9436938b191b80d9e4c0fc44"}, + {file = "Pillow-9.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:d3c6b54e304c60c4181da1c9dadf83e4a54fd266a99c70ba646a9baa626819eb"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:7ec6f6ce99dab90b52da21cf0dc519e21095e332ff3b399a357c187b1a5eee32"}, + {file = "Pillow-9.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:560737e70cb9c6255d6dcba3de6578a9e2ec4b573659943a5e7e4af13f298f5c"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96e88745a55b88a7c64fa49bceff363a1a27d9a64e04019c2281049444a571e3"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d9c206c29b46cfd343ea7cdfe1232443072bbb270d6a46f59c259460db76779a"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cfcc2c53c06f2ccb8976fb5c71d448bdd0a07d26d8e07e321c103416444c7ad1"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a0f9bb6c80e6efcde93ffc51256d5cfb2155ff8f78292f074f60f9e70b942d99"}, + {file = "Pillow-9.5.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:8d935f924bbab8f0a9a28404422da8af4904e36d5c33fc6f677e4c4485515625"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fed1e1cf6a42577953abbe8e6cf2fe2f566daebde7c34724ec8803c4c0cda579"}, + {file = "Pillow-9.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c1170d6b195555644f0616fd6ed929dfcf6333b8675fcca044ae5ab110ded296"}, + {file = "Pillow-9.5.0-cp311-cp311-win32.whl", hash = "sha256:54f7102ad31a3de5666827526e248c3530b3a33539dbda27c6843d19d72644ec"}, + {file = "Pillow-9.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:cfa4561277f677ecf651e2b22dc43e8f5368b74a25a8f7d1d4a3a243e573f2d4"}, + {file = "Pillow-9.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:965e4a05ef364e7b973dd17fc765f42233415974d773e82144c9bbaaaea5d089"}, + {file = "Pillow-9.5.0-cp312-cp312-win32.whl", hash = "sha256:22baf0c3cf0c7f26e82d6e1adf118027afb325e703922c8dfc1d5d0156bb2eeb"}, + {file = "Pillow-9.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:432b975c009cf649420615388561c0ce7cc31ce9b2e374db659ee4f7d57a1f8b"}, + {file = "Pillow-9.5.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:5d4ebf8e1db4441a55c509c4baa7a0587a0210f7cd25fcfe74dbbce7a4bd1906"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:375f6e5ee9620a271acb6820b3d1e94ffa8e741c0601db4c0c4d3cb0a9c224bf"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99eb6cafb6ba90e436684e08dad8be1637efb71c4f2180ee6b8f940739406e78"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2dfaaf10b6172697b9bceb9a3bd7b951819d1ca339a5ef294d1f1ac6d7f63270"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:763782b2e03e45e2c77d7779875f4432e25121ef002a41829d8868700d119392"}, + {file = "Pillow-9.5.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:35f6e77122a0c0762268216315bf239cf52b88865bba522999dc38f1c52b9b47"}, + {file = "Pillow-9.5.0-cp37-cp37m-win32.whl", hash = "sha256:aca1c196f407ec7cf04dcbb15d19a43c507a81f7ffc45b690899d6a76ac9fda7"}, + {file = "Pillow-9.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:322724c0032af6692456cd6ed554bb85f8149214d97398bb80613b04e33769f6"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:a0aa9417994d91301056f3d0038af1199eb7adc86e646a36b9e050b06f526597"}, + {file = "Pillow-9.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f8286396b351785801a976b1e85ea88e937712ee2c3ac653710a4a57a8da5d9c"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c830a02caeb789633863b466b9de10c015bded434deb3ec87c768e53752ad22a"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fbd359831c1657d69bb81f0db962905ee05e5e9451913b18b831febfe0519082"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8fc330c3370a81bbf3f88557097d1ea26cd8b019d6433aa59f71195f5ddebbf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:7002d0797a3e4193c7cdee3198d7c14f92c0836d6b4a3f3046a64bd1ce8df2bf"}, + {file = "Pillow-9.5.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:229e2c79c00e85989a34b5981a2b67aa079fd08c903f0aaead522a1d68d79e51"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:9adf58f5d64e474bed00d69bcd86ec4bcaa4123bfa70a65ce72e424bfb88ed96"}, + {file = "Pillow-9.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:662da1f3f89a302cc22faa9f14a262c2e3951f9dbc9617609a47521c69dd9f8f"}, + {file = "Pillow-9.5.0-cp38-cp38-win32.whl", hash = "sha256:6608ff3bf781eee0cd14d0901a2b9cc3d3834516532e3bd673a0a204dc8615fc"}, + {file = "Pillow-9.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:e49eb4e95ff6fd7c0c402508894b1ef0e01b99a44320ba7d8ecbabefddcc5569"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:482877592e927fd263028c105b36272398e3e1be3269efda09f6ba21fd83ec66"}, + {file = "Pillow-9.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3ded42b9ad70e5f1754fb7c2e2d6465a9c842e41d178f262e08b8c85ed8a1d8e"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c446d2245ba29820d405315083d55299a796695d747efceb5717a8b450324115"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aca1152d93dcc27dc55395604dcfc55bed5f25ef4c98716a928bacba90d33a3"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:608488bdcbdb4ba7837461442b90ea6f3079397ddc968c31265c1e056964f1ef"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:60037a8db8750e474af7ffc9faa9b5859e6c6d0a50e55c45576bf28be7419705"}, + {file = "Pillow-9.5.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:07999f5834bdc404c442146942a2ecadd1cb6292f5229f4ed3b31e0a108746b1"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a127ae76092974abfbfa38ca2d12cbeddcdeac0fb71f9627cc1135bedaf9d51a"}, + {file = "Pillow-9.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:489f8389261e5ed43ac8ff7b453162af39c3e8abd730af8363587ba64bb2e865"}, + {file = "Pillow-9.5.0-cp39-cp39-win32.whl", hash = "sha256:9b1af95c3a967bf1da94f253e56b6286b50af23392a886720f563c547e48e964"}, + {file = "Pillow-9.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:77165c4a5e7d5a284f10a6efaa39a0ae8ba839da344f20b111d62cc932fa4e5d"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:833b86a98e0ede388fa29363159c9b1a294b0905b5128baf01db683672f230f5"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aaf305d6d40bd9632198c766fb64f0c1a83ca5b667f16c1e79e1661ab5060140"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0852ddb76d85f127c135b6dd1f0bb88dbb9ee990d2cd9aa9e28526c93e794fba"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:91ec6fe47b5eb5a9968c79ad9ed78c342b1f97a091677ba0e012701add857829"}, + {file = "Pillow-9.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:cb841572862f629b99725ebaec3287fc6d275be9b14443ea746c1dd325053cbd"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:c380b27d041209b849ed246b111b7c166ba36d7933ec6e41175fd15ab9eb1572"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7c9af5a3b406a50e313467e3565fc99929717f780164fe6fbb7704edba0cebbe"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5671583eab84af046a397d6d0ba25343c00cd50bce03787948e0fff01d4fd9b1"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:84a6f19ce086c1bf894644b43cd129702f781ba5751ca8572f08aa40ef0ab7b7"}, + {file = "Pillow-9.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:1e7723bd90ef94eda669a3c2c19d549874dd5badaeefabefd26053304abe5799"}, + {file = "Pillow-9.5.0.tar.gz", hash = "sha256:bf548479d336726d7a0eceb6e767e179fbde37833ae42794602631a070d630f1"}, ] [package.extras] -docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-issues (>=3.0.1)", "sphinx-removed-in", "sphinxext-opengraph"] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] [[package]] name = "pkgutil-resolve-name" version = "1.3.10" description = "Resolve a name to an object." -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1121,33 +1130,31 @@ files = [ [[package]] name = "platformdirs" -version = "3.0.0" +version = "3.10.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.0.0-py3-none-any.whl", hash = "sha256:b1d5eb14f221506f50d6604a561f4c5786d9e80355219694a1b244bcd96f4567"}, - {file = "platformdirs-3.0.0.tar.gz", hash = "sha256:8a1228abb1ef82d788f74139988b137e78692984ec7b08eaa6c65f1723af28f9"}, + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, ] [package.dependencies] -typing-extensions = {version = ">=4.4", markers = "python_version < \"3.8\""} +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.2.2)", "pytest (>=7.2.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] [[package]] name = "pluggy" -version = "1.0.0" +version = "1.2.0" description = "plugin and hook calling mechanisms for python" -category = "dev" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, - {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, ] [package.dependencies] @@ -1161,7 +1168,6 @@ testing = ["pytest", "pytest-benchmark"] name = "pre-commit" version = "2.21.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1181,7 +1187,6 @@ virtualenv = ">=20.10.0" name = "py-cpuinfo" version = "9.0.0" description = "Get CPU info with pure Python" -category = "dev" optional = false python-versions = "*" files = [ @@ -1189,69 +1194,15 @@ files = [ {file = "py_cpuinfo-9.0.0-py3-none-any.whl", hash = "sha256:859625bc251f64e21f077d099d4162689c762b5d6a4c3c97553d56241c9674d5"}, ] -[[package]] -name = "pydantic" -version = "1.10.5" -description = "Data validation and settings management using python type hints" -category = "dev" -optional = true -python-versions = ">=3.7" -files = [ - {file = "pydantic-1.10.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5920824fe1e21cbb3e38cf0f3dd24857c8959801d1031ce1fac1d50857a03bfb"}, - {file = "pydantic-1.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3bb99cf9655b377db1a9e47fa4479e3330ea96f4123c6c8200e482704bf1eda2"}, - {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2185a3b3d98ab4506a3f6707569802d2d92c3a7ba3a9a35683a7709ea6c2aaa2"}, - {file = "pydantic-1.10.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f582cac9d11c227c652d3ce8ee223d94eb06f4228b52a8adaafa9fa62e73d5c9"}, - {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c9e5b778b6842f135902e2d82624008c6a79710207e28e86966cd136c621bfee"}, - {file = "pydantic-1.10.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:72ef3783be8cbdef6bca034606a5de3862be6b72415dc5cb1fb8ddbac110049a"}, - {file = "pydantic-1.10.5-cp310-cp310-win_amd64.whl", hash = "sha256:45edea10b75d3da43cfda12f3792833a3fa70b6eee4db1ed6aed528cef17c74e"}, - {file = "pydantic-1.10.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:63200cd8af1af2c07964546b7bc8f217e8bda9d0a2ef0ee0c797b36353914984"}, - {file = "pydantic-1.10.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:305d0376c516b0dfa1dbefeae8c21042b57b496892d721905a6ec6b79494a66d"}, - {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd326aff5d6c36f05735c7c9b3d5b0e933b4ca52ad0b6e4b38038d82703d35b"}, - {file = "pydantic-1.10.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bb0452d7b8516178c969d305d9630a3c9b8cf16fcf4713261c9ebd465af0d73"}, - {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9a9d9155e2a9f38b2eb9374c88f02fd4d6851ae17b65ee786a87d032f87008f8"}, - {file = "pydantic-1.10.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f836444b4c5ece128b23ec36a446c9ab7f9b0f7981d0d27e13a7c366ee163f8a"}, - {file = "pydantic-1.10.5-cp311-cp311-win_amd64.whl", hash = "sha256:8481dca324e1c7b715ce091a698b181054d22072e848b6fc7895cd86f79b4449"}, - {file = "pydantic-1.10.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:87f831e81ea0589cd18257f84386bf30154c5f4bed373b7b75e5cb0b5d53ea87"}, - {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ce1612e98c6326f10888df951a26ec1a577d8df49ddcaea87773bfbe23ba5cc"}, - {file = "pydantic-1.10.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:58e41dd1e977531ac6073b11baac8c013f3cd8706a01d3dc74e86955be8b2c0c"}, - {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:6a4b0aab29061262065bbdede617ef99cc5914d1bf0ddc8bcd8e3d7928d85bd6"}, - {file = "pydantic-1.10.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:36e44a4de37b8aecffa81c081dbfe42c4d2bf9f6dff34d03dce157ec65eb0f15"}, - {file = "pydantic-1.10.5-cp37-cp37m-win_amd64.whl", hash = "sha256:261f357f0aecda005934e413dfd7aa4077004a174dafe414a8325e6098a8e419"}, - {file = "pydantic-1.10.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b429f7c457aebb7fbe7cd69c418d1cd7c6fdc4d3c8697f45af78b8d5a7955760"}, - {file = "pydantic-1.10.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:663d2dd78596c5fa3eb996bc3f34b8c2a592648ad10008f98d1348be7ae212fb"}, - {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51782fd81f09edcf265823c3bf43ff36d00db246eca39ee765ef58dc8421a642"}, - {file = "pydantic-1.10.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c428c0f64a86661fb4873495c4fac430ec7a7cef2b8c1c28f3d1a7277f9ea5ab"}, - {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:76c930ad0746c70f0368c4596020b736ab65b473c1f9b3872310a835d852eb19"}, - {file = "pydantic-1.10.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:3257bd714de9db2102b742570a56bf7978e90441193acac109b1f500290f5718"}, - {file = "pydantic-1.10.5-cp38-cp38-win_amd64.whl", hash = "sha256:f5bee6c523d13944a1fdc6f0525bc86dbbd94372f17b83fa6331aabacc8fd08e"}, - {file = "pydantic-1.10.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:532e97c35719f137ee5405bd3eeddc5c06eb91a032bc755a44e34a712420daf3"}, - {file = "pydantic-1.10.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ca9075ab3de9e48b75fa8ccb897c34ccc1519177ad8841d99f7fd74cf43be5bf"}, - {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd46a0e6296346c477e59a954da57beaf9c538da37b9df482e50f836e4a7d4bb"}, - {file = "pydantic-1.10.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3353072625ea2a9a6c81ad01b91e5c07fa70deb06368c71307529abf70d23325"}, - {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3f9d9b2be177c3cb6027cd67fbf323586417868c06c3c85d0d101703136e6b31"}, - {file = "pydantic-1.10.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b473d00ccd5c2061fd896ac127b7755baad233f8d996ea288af14ae09f8e0d1e"}, - {file = "pydantic-1.10.5-cp39-cp39-win_amd64.whl", hash = "sha256:5f3bc8f103b56a8c88021d481410874b1f13edf6e838da607dcb57ecff9b4594"}, - {file = "pydantic-1.10.5-py3-none-any.whl", hash = "sha256:7c5b94d598c90f2f46b3a983ffb46ab806a67099d118ae0da7ef21a2a4033b28"}, - {file = "pydantic-1.10.5.tar.gz", hash = "sha256:9e337ac83686645a46db0e825acceea8e02fca4062483f40e9ae178e8bd1103a"}, -] - -[package.dependencies] -typing-extensions = ">=4.2.0" - -[package.extras] -dotenv = ["python-dotenv (>=0.10.4)"] -email = ["email-validator (>=1.0.3)"] - [[package]] name = "pygments" -version = "2.14.0" +version = "2.16.1" description = "Pygments is a syntax highlighting package written in Python." -category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "Pygments-2.14.0-py3-none-any.whl", hash = "sha256:fa7bd7bd2771287c0de303af8bfdfc731f51bd2c6a47ab69d117138893b82717"}, - {file = "Pygments-2.14.0.tar.gz", hash = "sha256:b3ed06a9e8ac9a9aae5a6f5dbe78a8a58655d17b43b93c078f094ddc476ae297"}, + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, ] [package.extras] @@ -1259,14 +1210,13 @@ plugins = ["importlib-metadata"] [[package]] name = "pyparsing" -version = "3.0.9" +version = "3.1.1" description = "pyparsing module - Classes and methods to define and execute parsing grammars" -category = "main" optional = false python-versions = ">=3.6.8" files = [ - {file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"}, - {file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"}, + {file = "pyparsing-3.1.1-py3-none-any.whl", hash = "sha256:32c7c0b711493c72ff18a981d24f28aaf9c1fb7ed5e9667c9e84e3db623bdbfb"}, + {file = "pyparsing-3.1.1.tar.gz", hash = "sha256:ede28a1a32462f5a9705e07aea48001a08f7cf81a021585011deba701581a0db"}, ] [package.extras] @@ -1276,7 +1226,6 @@ diagrams = ["jinja2", "railroad-diagrams"] name = "pyrsistent" version = "0.19.3" description = "Persistent/Functional/Immutable data structures" -category = "main" optional = false python-versions = ">=3.7" files = [ @@ -1311,18 +1260,16 @@ files = [ [[package]] name = "pytest" -version = "7.2.1" +version = "7.4.2" description = "pytest: simple powerful testing with Python" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.1-py3-none-any.whl", hash = "sha256:c7c6ca206e93355074ae32f7403e8ea12163b1163c976fee7d4d84027c162be5"}, - {file = "pytest-7.2.1.tar.gz", hash = "sha256:d45e0952f3727241918b8fd0f376f5ff6b301cc0777c6f9a556935c92d8a7d42"}, + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} @@ -1332,13 +1279,12 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-benchmark" version = "4.0.0" description = "A ``pytest`` fixture for benchmarking code. It will group the tests into rounds that are calibrated to the chosen timer." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1357,14 +1303,13 @@ histogram = ["pygal", "pygaljs"] [[package]] name = "pytest-xdist" -version = "3.2.0" +version = "3.3.1" description = "pytest xdist plugin for distributed testing, most importantly across multiple CPUs" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-xdist-3.2.0.tar.gz", hash = "sha256:fa10f95a2564cd91652f2d132725183c3b590d9fdcdec09d3677386ecf4c1ce9"}, - {file = "pytest_xdist-3.2.0-py3-none-any.whl", hash = "sha256:336098e3bbd8193276867cc87db8b22903c3927665dff9d1ac8684c02f597b68"}, + {file = "pytest-xdist-3.3.1.tar.gz", hash = "sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93"}, + {file = "pytest_xdist-3.3.1-py3-none-any.whl", hash = "sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"}, ] [package.dependencies] @@ -1380,7 +1325,6 @@ testing = ["filelock"] name = "python-dateutil" version = "2.8.2" description = "Extensions to the standard Python datetime module" -category = "main" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ @@ -1393,83 +1337,80 @@ six = ">=1.5" [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.3.post1" description = "World timezone definitions, modern and historical" -category = "main" optional = false python-versions = "*" files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, + {file = "pytz-2023.3.post1-py2.py3-none-any.whl", hash = "sha256:ce42d816b81b68506614c11e8937d3aa9e41007ceb50bfdcb0749b921bf646c7"}, + {file = "pytz-2023.3.post1.tar.gz", hash = "sha256:7b4fddbeb94a1eba4b557da24f19fdf9db575192544270a9101d8509f9f43d7b"}, ] [[package]] name = "pyyaml" -version = "6.0" +version = "6.0.1" description = "YAML parser and emitter for Python" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "PyYAML-6.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53"}, - {file = "PyYAML-6.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b"}, - {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"}, - {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"}, - {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"}, - {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"}, - {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"}, - {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"}, - {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"}, - {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"}, - {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4"}, - {file = "PyYAML-6.0-cp36-cp36m-win32.whl", hash = "sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293"}, - {file = "PyYAML-6.0-cp36-cp36m-win_amd64.whl", hash = "sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57"}, - {file = "PyYAML-6.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4"}, - {file = "PyYAML-6.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9"}, - {file = "PyYAML-6.0-cp37-cp37m-win32.whl", hash = "sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737"}, - {file = "PyYAML-6.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d"}, - {file = "PyYAML-6.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34"}, - {file = "PyYAML-6.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287"}, - {file = "PyYAML-6.0-cp38-cp38-win32.whl", hash = "sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78"}, - {file = "PyYAML-6.0-cp38-cp38-win_amd64.whl", hash = "sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b"}, - {file = "PyYAML-6.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3"}, - {file = "PyYAML-6.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0"}, - {file = "PyYAML-6.0-cp39-cp39-win32.whl", hash = "sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb"}, - {file = "PyYAML-6.0-cp39-cp39-win_amd64.whl", hash = "sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c"}, - {file = "PyYAML-6.0.tar.gz", hash = "sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, ] [[package]] name = "requests" -version = "2.28.2" +version = "2.31.0" description = "Python HTTP for Humans." -category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -1479,7 +1420,6 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] name = "requests-file" version = "1.5.1" description = "File transport adapter for Requests" -category = "main" optional = false python-versions = "*" files = [ @@ -1493,14 +1433,13 @@ six = "*" [[package]] name = "requests-mock" -version = "1.10.0" +version = "1.11.0" description = "Mock out responses from the requests package" -category = "dev" optional = false python-versions = "*" files = [ - {file = "requests-mock-1.10.0.tar.gz", hash = "sha256:59c9c32419a9fb1ae83ec242d98e889c45bd7d7a65d48375cc243ec08441658b"}, - {file = "requests_mock-1.10.0-py2.py3-none-any.whl", hash = "sha256:2fdbb637ad17ee15c06f33d31169e71bf9fe2bdb7bc9da26185be0dd8d842699"}, + {file = "requests-mock-1.11.0.tar.gz", hash = "sha256:ef10b572b489a5f28e09b708697208c4a3b2b89ef80a9f01584340ea357ec3c4"}, + {file = "requests_mock-1.11.0-py2.py3-none-any.whl", hash = "sha256:f7fae383f228633f6bececebdab236c478ace2284d6292c6e7e2867b9ab74d15"}, ] [package.dependencies] @@ -1509,13 +1448,12 @@ six = "*" [package.extras] fixture = ["fixtures"] -test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "testrepository (>=0.0.18)", "testtools"] +test = ["fixtures", "mock", "purl", "pytest", "requests-futures", "sphinx", "testtools"] [[package]] name = "responses" version = "0.22.0" description = "A utility library for mocking out the `requests` Python library." -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1535,19 +1473,18 @@ tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asy [[package]] name = "rich" -version = "13.3.1" +version = "13.5.2" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" -category = "dev" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.3.1-py3-none-any.whl", hash = "sha256:8aa57747f3fc3e977684f0176a88e789be314a99f99b43b75d1e9cb5dc6db9e9"}, - {file = "rich-13.3.1.tar.gz", hash = "sha256:125d96d20c92b946b983d0d392b84ff945461e5a06d3867e9f9e575f8697b67f"}, + {file = "rich-13.5.2-py3-none-any.whl", hash = "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808"}, + {file = "rich-13.5.2.tar.gz", hash = "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"}, ] [package.dependencies] -markdown-it-py = ">=2.1.0,<3.0.0" -pygments = ">=2.14.0,<3.0.0" +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} [package.extras] @@ -1555,26 +1492,24 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "setuptools" -version = "67.3.2" +version = "68.0.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.3.2-py3-none-any.whl", hash = "sha256:bb6d8e508de562768f2027902929f8523932fcd1fb784e6d573d2cafac995a48"}, - {file = "setuptools-67.3.2.tar.gz", hash = "sha256:95f00380ef2ffa41d9bba85d95b27689d923c93dfbafed4aecd7cf988a25e012"}, + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8 (<5)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] [[package]] name = "six" version = "1.16.0" description = "Python 2 and 3 compatibility utilities" -category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1586,7 +1521,6 @@ files = [ name = "snowballstemmer" version = "2.2.0" description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." -category = "main" optional = false python-versions = "*" files = [ @@ -1598,7 +1532,6 @@ files = [ name = "sphinx" version = "5.3.0" description = "Python documentation generator" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1634,7 +1567,6 @@ test = ["cython", "html5lib", "pytest (>=4.6)", "typed_ast"] name = "sphinx-data-viewer" version = "0.1.2" description = "Sphinx extension to show dta in an interacitve list view" -category = "main" optional = false python-versions = ">=3.6,<4.0" files = [ @@ -1644,35 +1576,10 @@ files = [ [package.extras] docs = ["sphinx (>=4,<5)"] -[[package]] -name = "sphinx-immaterial" -version = "0.7.3" -description = "Adaptation of mkdocs-material theme for the Sphinx documentation system" -category = "dev" -optional = true -python-versions = ">=3.7" -files = [ - {file = "sphinx_immaterial-0.7.3-py3-none-any.whl", hash = "sha256:674440fc4eb39aaa4ec9c098fd09b7cd696754438e93ddd539d19828bab0f509"}, - {file = "sphinx_immaterial-0.7.3.tar.gz", hash = "sha256:098e1069494fea1482601c33d6a124eff023d19b1616fdb6c46b482177f3e7b7"}, -] - -[package.dependencies] -markupsafe = "*" -pydantic = "*" -sphinx = ">=4.0" -typing-extensions = "*" - -[package.extras] -clang-format = ["clang-format"] -json = ["pyyaml"] -jsonschema-validation = ["jsonschema"] -keys = ["pymdown-extensions"] - [[package]] name = "sphinxcontrib-applehelp" version = "1.0.2" description = "sphinxcontrib-applehelp is a sphinx extension which outputs Apple help books" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1688,7 +1595,6 @@ test = ["pytest"] name = "sphinxcontrib-devhelp" version = "1.0.2" description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1704,7 +1610,6 @@ test = ["pytest"] name = "sphinxcontrib-htmlhelp" version = "2.0.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" -category = "main" optional = false python-versions = ">=3.6" files = [ @@ -1720,7 +1625,6 @@ test = ["html5lib", "pytest"] name = "sphinxcontrib-jsmath" version = "1.0.1" description = "A sphinx extension which renders display math in HTML via JavaScript" -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1733,13 +1637,12 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-plantuml" -version = "0.24.1" +version = "0.26" description = "Sphinx \"plantuml\" extension" -category = "dev" optional = false python-versions = "*" files = [ - {file = "sphinxcontrib-plantuml-0.24.1.tar.gz", hash = "sha256:39d2e4bc40d5e093126129a144f56b6ee15f58cfa5048b5948e63a11aff3b586"}, + {file = "sphinxcontrib-plantuml-0.26.tar.gz", hash = "sha256:adb3397d5cb0613632cd3dad7894381422bac24464c393cb050404dd6712b1a7"}, ] [package.dependencies] @@ -1752,7 +1655,6 @@ test = ["Pillow", "flake8", "pytest"] name = "sphinxcontrib-qthelp" version = "1.0.3" description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1768,7 +1670,6 @@ test = ["pytest"] name = "sphinxcontrib-serializinghtml" version = "1.1.5" description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." -category = "main" optional = false python-versions = ">=3.5" files = [ @@ -1780,11 +1681,25 @@ files = [ lint = ["docutils-stubs", "flake8", "mypy"] test = ["pytest"] +[[package]] +name = "syrupy" +version = "3.0.6" +description = "Pytest Snapshot Test Utility" +optional = false +python-versions = ">=3.7,<4" +files = [ + {file = "syrupy-3.0.6-py3-none-any.whl", hash = "sha256:9c18e22264026b34239bcc87ab7cc8d893eb17236ea7dae634217ea4f22a848d"}, + {file = "syrupy-3.0.6.tar.gz", hash = "sha256:583aa5ca691305c27902c3e29a1ce9da50ff9ab5f184c54b1dc124a16e4a6cf4"}, +] + +[package.dependencies] +colored = ">=1.3.92,<2.0.0" +pytest = ">=5.1.0,<8.0.0" + [[package]] name = "tabulate" version = "0.9.0" description = "Pretty-print tabular data" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1799,7 +1714,6 @@ widechars = ["wcwidth"] name = "toml" version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" -category = "dev" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" files = [ @@ -1811,7 +1725,6 @@ files = [ name = "tomli" version = "2.0.1" description = "A lil' TOML parser" -category = "dev" optional = false python-versions = ">=3.7" files = [ @@ -1821,70 +1734,83 @@ files = [ [[package]] name = "typed-ast" -version = "1.5.4" +version = "1.5.5" description = "a fork of Python 2 and 3 ast modules with type comment support" -category = "dev" optional = false python-versions = ">=3.6" files = [ - {file = "typed_ast-1.5.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:669dd0c4167f6f2cd9f57041e03c3c2ebf9063d0757dc89f79ba1daa2bfca9d4"}, - {file = "typed_ast-1.5.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:211260621ab1cd7324e0798d6be953d00b74e0428382991adfddb352252f1d62"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:267e3f78697a6c00c689c03db4876dd1efdfea2f251a5ad6555e82a26847b4ac"}, - {file = "typed_ast-1.5.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:c542eeda69212fa10a7ada75e668876fdec5f856cd3d06829e6aa64ad17c8dfe"}, - {file = "typed_ast-1.5.4-cp310-cp310-win_amd64.whl", hash = "sha256:a9916d2bb8865f973824fb47436fa45e1ebf2efd920f2b9f99342cb7fab93f72"}, - {file = "typed_ast-1.5.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:79b1e0869db7c830ba6a981d58711c88b6677506e648496b1f64ac7d15633aec"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a94d55d142c9265f4ea46fab70977a1944ecae359ae867397757d836ea5a3f47"}, - {file = "typed_ast-1.5.4-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:183afdf0ec5b1b211724dfef3d2cad2d767cbefac291f24d69b00546c1837fb6"}, - {file = "typed_ast-1.5.4-cp36-cp36m-win_amd64.whl", hash = "sha256:639c5f0b21776605dd6c9dbe592d5228f021404dafd377e2b7ac046b0349b1a1"}, - {file = "typed_ast-1.5.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf4afcfac006ece570e32d6fa90ab74a17245b83dfd6655a6f68568098345ff6"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed855bbe3eb3715fca349c80174cfcfd699c2f9de574d40527b8429acae23a66"}, - {file = "typed_ast-1.5.4-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6778e1b2f81dfc7bc58e4b259363b83d2e509a65198e85d5700dfae4c6c8ff1c"}, - {file = "typed_ast-1.5.4-cp37-cp37m-win_amd64.whl", hash = "sha256:0261195c2062caf107831e92a76764c81227dae162c4f75192c0d489faf751a2"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2efae9db7a8c05ad5547d522e7dbe62c83d838d3906a3716d1478b6c1d61388d"}, - {file = "typed_ast-1.5.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7d5d014b7daa8b0bf2eaef684295acae12b036d79f54178b92a2b6a56f92278f"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:370788a63915e82fd6f212865a596a0fefcbb7d408bbbb13dea723d971ed8bdc"}, - {file = "typed_ast-1.5.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4e964b4ff86550a7a7d56345c7864b18f403f5bd7380edf44a3c1fb4ee7ac6c6"}, - {file = "typed_ast-1.5.4-cp38-cp38-win_amd64.whl", hash = "sha256:683407d92dc953c8a7347119596f0b0e6c55eb98ebebd9b23437501b28dcbb8e"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:4879da6c9b73443f97e731b617184a596ac1235fe91f98d279a7af36c796da35"}, - {file = "typed_ast-1.5.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3e123d878ba170397916557d31c8f589951e353cc95fb7f24f6bb69adc1a8a97"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ebd9d7f80ccf7a82ac5f88c521115cc55d84e35bf8b446fcd7836eb6b98929a3"}, - {file = "typed_ast-1.5.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98f80dee3c03455e92796b58b98ff6ca0b2a6f652120c263efdba4d6c5e58f72"}, - {file = "typed_ast-1.5.4-cp39-cp39-win_amd64.whl", hash = "sha256:0fdbcf2fef0ca421a3f5912555804296f0b0960f0418c440f5d6d3abb549f3e1"}, - {file = "typed_ast-1.5.4.tar.gz", hash = "sha256:39e21ceb7388e4bb37f4c679d72707ed46c2fbf2a5609b8b8ebc4b067d977df2"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, ] [[package]] name = "types-docutils" -version = "0.19.1.4" +version = "0.20.0.3" description = "Typing stubs for docutils" -category = "dev" optional = false python-versions = "*" files = [ - {file = "types-docutils-0.19.1.4.tar.gz", hash = "sha256:1b64b21b609ff1fc7791d3d930f14b56b36ad09029fd97e45e34cc889d671b5f"}, - {file = "types_docutils-0.19.1.4-py3-none-any.whl", hash = "sha256:870d71f3663141f67a3c59d26d2c54a8c478c842208bb0b345fbf6036f49f561"}, + {file = "types-docutils-0.20.0.3.tar.gz", hash = "sha256:4928e790f42b99d5833990f99c8dd9fa9f16825f6ed30380ca981846d36870cd"}, + {file = "types_docutils-0.20.0.3-py3-none-any.whl", hash = "sha256:a930150d8e01a9170f9bca489f46808ddebccdd8bc1e47c07968a77e49fb9321"}, ] [[package]] name = "types-requests" -version = "2.28.11.13" +version = "2.31.0.2" description = "Typing stubs for requests" -category = "dev" optional = false python-versions = "*" files = [ - {file = "types-requests-2.28.11.13.tar.gz", hash = "sha256:3fd332842e8759ea5f7eb7789df8aa772ba155216ccf10ef4aa3b0e5b42e1b46"}, - {file = "types_requests-2.28.11.13-py3-none-any.whl", hash = "sha256:94896f6f8e9f3db11e422c6e3e4abbc5d7ccace853eac74b23bdd65eeee3cdee"}, + {file = "types-requests-2.31.0.2.tar.gz", hash = "sha256:6aa3f7faf0ea52d728bb18c0a0d1522d9bfd8c72d26ff6f61bfc3d06a411cf40"}, + {file = "types_requests-2.31.0.2-py3-none-any.whl", hash = "sha256:56d181c85b5925cbc59f4489a57e72a8b2166f18273fd8ba7b6fe0c0b986f12a"}, ] [package.dependencies] -types-urllib3 = "<1.27" +types-urllib3 = "*" [[package]] name = "types-setuptools" version = "65.7.0.4" description = "Typing stubs for setuptools" -category = "dev" optional = false python-versions = "*" files = [ @@ -1897,100 +1823,91 @@ types-docutils = "*" [[package]] name = "types-toml" -version = "0.10.8.4" +version = "0.10.8.7" description = "Typing stubs for toml" -category = "dev" optional = false python-versions = "*" files = [ - {file = "types-toml-0.10.8.4.tar.gz", hash = "sha256:c8748dd225b28eb80ce712e2d7d61b57599815e7b48d07ef53df51ed148fa6b1"}, - {file = "types_toml-0.10.8.4-py3-none-any.whl", hash = "sha256:306b1bb8b5bbc5f1b60387dbcc4b489e79f8490ce20e93af5f422a68b470d94b"}, + {file = "types-toml-0.10.8.7.tar.gz", hash = "sha256:58b0781c681e671ff0b5c0319309910689f4ab40e8a2431e205d70c94bb6efb1"}, + {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, ] [[package]] name = "types-urllib3" -version = "1.26.25.6" +version = "1.26.25.14" description = "Typing stubs for urllib3" -category = "dev" optional = false python-versions = "*" files = [ - {file = "types-urllib3-1.26.25.6.tar.gz", hash = "sha256:35586727cbd7751acccf2c0f34a88baffc092f435ab62458f10776466590f2d5"}, - {file = "types_urllib3-1.26.25.6-py3-none-any.whl", hash = "sha256:a6c23c41bd03e542eaee5423a018f833077b51c4bf9ceb5aa544e12b812d5604"}, + {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, + {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, ] [[package]] name = "typing-extensions" -version = "4.5.0" +version = "4.7.1" description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, - {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, ] [[package]] name = "urllib3" -version = "1.26.14" +version = "2.0.4" description = "HTTP library with thread-safe connection pooling, file post, and more." -category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.14-py2.py3-none-any.whl", hash = "sha256:75edcdc2f7d85b137124a6c3c9fc3933cdeaa12ecb9a6a959f22797a0feca7e1"}, - {file = "urllib3-1.26.14.tar.gz", hash = "sha256:076907bf8fd355cde77728471316625a4d2f7e713c125f51953bb5b3eecf4f72"}, + {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, + {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.19.0" +version = "20.24.5" description = "Virtual Python Environment builder" -category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.19.0-py3-none-any.whl", hash = "sha256:54eb59e7352b573aa04d53f80fc9736ed0ad5143af445a1e539aada6eb947dd1"}, - {file = "virtualenv-20.19.0.tar.gz", hash = "sha256:37a640ba82ed40b226599c522d411e4be5edb339a0c0de030c0dc7b646d61590"}, + {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, + {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, ] [package.dependencies] -distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} -platformdirs = ">=2.4,<4" +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} +platformdirs = ">=3.9.1,<4" [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [[package]] name = "zipp" -version = "3.13.0" +version = "3.15.0" description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "zipp-3.13.0-py3-none-any.whl", hash = "sha256:e8b2a36ea17df80ffe9e2c4fda3f693c3dad6df1697d3cd3af232db680950b0b"}, - {file = "zipp-3.13.0.tar.gz", hash = "sha256:23f70e964bc11a34cef175bc90ba2914e1e4545ea1e3e2f67c079671883f9cb6"}, + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, ] [package.extras] docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["flake8 (<5)", "func-timeout", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[extras] -docs = ["sphinx"] -immaterial = [] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] [metadata] lock-version = "2.0" python-versions = ">=3.7.0,<4.0" -content-hash = "27f4d83ca2c7761c9440fc0979fe8975749d3b2ce6ff44c276fa9b2948f8deb8" +content-hash = "74d9e2375488c28c1cd6286e8cf27985fa7fb5847f81f5c678a94a086dbaf626" diff --git a/pyproject.toml b/pyproject.toml index b931398e7..449f8bb3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ pre-commit = "^2" lxml = "^4.6.5" pytest = "^7" pytest-xdist="*" # parallelisation +syrupy = ">=3,<5" responses = "^0.22.0" requests-mock = ">=1.9.3" tabulate = "^0.9.0" @@ -107,13 +108,13 @@ ignore_missing_imports = true module = [ 'sphinx_needs.api.need', 'sphinx_needs.directives.needuml', - 'sphinx_needs.functions.functions', ] ignore_errors = true [[tool.mypy.overrides]] module = [ - "sphinx_needs.directives.needextend" + "sphinx_needs.directives.needextend", + "sphinx_needs.functions.functions", ] # TODO dynamically overriding TypeDict keys is a bit tricky disable_error_code = "literal-required" diff --git a/sphinx_needs/api/need.py b/sphinx_needs/api/need.py index 8af32bfd7..5ae06f619 100644 --- a/sphinx_needs/api/need.py +++ b/sphinx_needs/api/need.py @@ -28,7 +28,7 @@ from sphinx_needs.logging import get_logger from sphinx_needs.nodes import Need from sphinx_needs.roles.need_part import find_parts, update_need_with_parts -from sphinx_needs.utils import jinja_parse, unwrap +from sphinx_needs.utils import jinja_parse logger = get_logger(__name__) @@ -337,6 +337,12 @@ def run(): "external_css": external_css or "external_link", "is_modified": False, # needed by needextend "modifications": 0, # needed by needextend + # these are set later in the analyse_need_locations transform + "sections": [], + "section_name": "", + "signature": "", + "parent_needs": [], + "parent_need": "", } needs_extra_option_names = list(NEEDS_CONFIG.extra_options) _merge_extra_options(needs_info, kwargs, needs_extra_option_names) @@ -436,8 +442,9 @@ def run(): node_need.line = needs_info["lineno"] if needs_info["hide"]: - # add node to doctree, so we can later compute the containing section(s) - # (for use with section filters) + # still add node to doctree, + # so we can later compute its relative location in the document + # (see analyse_need_locations function) node_need["hidden"] = True return [node_need] @@ -505,7 +512,7 @@ def del_need(app: Sphinx, need_id: str) -> None: :param app: Sphinx application object. :param need_id: Sphinx need id. """ - env = unwrap(app.env) + env = app.env needs = SphinxNeedsData(env).get_or_create_needs() if need_id in needs: del needs[need_id] @@ -739,6 +746,7 @@ def _merge_global_options(app: Sphinx, needs_info, global_options) -> None: """Add all global defined options to needs_info""" if global_options is None: return + config = NeedsSphinxConfig(app.config) for key, value in global_options.items(): # If key already exists in needs_info, this global_option got overwritten manually in current need if key in needs_info and needs_info[key]: @@ -755,7 +763,7 @@ def _merge_global_options(app: Sphinx, needs_info, global_options) -> None: for single_value in values: if len(single_value) < 2 or len(single_value) > 3: raise NeedsInvalidException(f"global option tuple has wrong amount of parameters: {key}") - if filter_single_need(app, needs_info, single_value[1]): + if filter_single_need(needs_info, config, single_value[1]): # Set value, if filter has matched needs_info[key] = single_value[0] elif len(single_value) == 3 and (key not in needs_info.keys() or len(str(needs_info[key])) > 0): diff --git a/sphinx_needs/builder.py b/sphinx_needs/builder.py index 4b1277837..454cc95b9 100644 --- a/sphinx_needs/builder.py +++ b/sphinx_needs/builder.py @@ -10,7 +10,6 @@ from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.logging import get_logger from sphinx_needs.needsfile import NeedsList -from sphinx_needs.utils import unwrap log = get_logger(__name__) @@ -25,7 +24,7 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None: pass def finish(self) -> None: - env = unwrap(self.env) + env = self.env data = SphinxNeedsData(env) filters = data.get_or_create_filters() version = getattr(env.config, "version", "unset") @@ -49,7 +48,9 @@ def finish(self) -> None: from sphinx_needs.filter_common import filter_needs filter_string = needs_config.builder_filter - filtered_needs: List[NeedsInfoType] = filter_needs(self.app, data.get_or_create_needs().values(), filter_string) + filtered_needs: List[NeedsInfoType] = filter_needs( + data.get_or_create_needs().values(), needs_config, filter_string + ) for need in filtered_needs: needs_list.add_need(version, need) @@ -82,7 +83,7 @@ def get_target_uri(self, _docname: str, _typ: Optional[str] = None) -> str: def build_needs_json(app: Sphinx, _exception: Exception) -> None: - env = unwrap(app.env) + env = app.env if not NeedsSphinxConfig(env.config).build_json: return @@ -107,7 +108,7 @@ def write_doc(self, docname: str, doctree: nodes.document) -> None: pass def finish(self) -> None: - env = unwrap(self.env) + env = self.env needumls = SphinxNeedsData(env).get_or_create_umls().values() for needuml in needumls: @@ -140,7 +141,7 @@ def get_target_uri(self, _docname: str, _typ: Optional[str] = None) -> str: def build_needumls_pumls(app: Sphinx, _exception: Exception) -> None: - env = unwrap(app.env) + env = app.env config = NeedsSphinxConfig(env.config) if not config.build_needumls: @@ -160,3 +161,74 @@ def build_needumls_pumls(app: Sphinx, _exception: Exception) -> None: needs_builder.set_environment(env) needs_builder.finish() + + +class NeedsIdBuilder(Builder): + """Json builder for needs, which creates separate json-files per need""" + + name = "needs_id" + format = "needs" + file_suffix = ".txt" + links_suffix = None + + def write_doc(self, docname: str, doctree: nodes.document) -> None: + pass + + def finish(self) -> None: + env = self.env + data = SphinxNeedsData(env) + needs = data.get_or_create_needs().values() # We need a list of needs for later filter checks + version = getattr(env.config, "version", "unset") + needs_config = NeedsSphinxConfig(env.config) + filter_string = needs_config.builder_filter + from sphinx_needs.filter_common import filter_needs + + filtered_needs = filter_needs(needs, needs_config, filter_string) + needs_build_json_per_id_path = needs_config.build_json_per_id_path + needs_dir = os.path.join(self.outdir, needs_build_json_per_id_path) + if not os.path.exists(needs_dir): + os.makedirs(needs_dir, exist_ok=True) + for need in filtered_needs: + needs_list = NeedsList(env.config, self.outdir, self.srcdir) + needs_list.wipe_version(version) + needs_list.add_need(version, need) + id = need["id"] + try: + file_name = f"{id}.json" + needs_list.write_json(file_name, needs_dir) + except Exception as e: + log.error(f"Needs-ID Builder {id} error: {e}") + log.info("Needs_id successfully exported") + + def get_outdated_docs(self) -> Iterable[str]: + return [] + + def prepare_writing(self, _docnames: Set[str]) -> None: + pass + + def write_doc_serialized(self, _docname: str, _doctree: nodes.document) -> None: + pass + + def cleanup(self) -> None: + pass + + def get_target_uri(self, _docname: str, _typ: Optional[str] = None) -> str: + return "" + + +def build_needs_id_json(app: Sphinx, _exception: Exception) -> None: + env = app.env + + if not NeedsSphinxConfig(env.config).build_json_per_id: + return + + # Do not create an additional needs_json for every needs_id, if builder is already "needs_id". + if isinstance(app.builder, NeedsIdBuilder): + return + try: + needs_id_builder = NeedsIdBuilder(app, env) + except TypeError: + needs_id_builder = NeedsIdBuilder(app) + needs_id_builder.set_environment(env) + + needs_id_builder.finish() diff --git a/sphinx_needs/config.py b/sphinx_needs/config.py index bb0c4ddc8..0ba6c559f 100644 --- a/sphinx_needs/config.py +++ b/sphinx_needs/config.py @@ -8,6 +8,12 @@ from sphinx_needs.defaults import DEFAULT_DIAGRAM_TEMPLATE, NEEDS_TABLES_CLASSES +try: + from typing import Literal, TypedDict +except ImportError: + # introduced in python 3.8 + from typing_extensions import Literal, TypedDict # type: ignore + if TYPE_CHECKING: from sphinx.util.logging import SphinxLoggerAdapter @@ -54,6 +60,17 @@ def warnings(self) -> dict[str, str | Callable[[NeedsInfoType, SphinxLoggerAdapt NEEDS_CONFIG = Config() +class ConstraintFailedType(TypedDict): + """Defines what to do if a constraint is not fulfilled""" + + on_fail: list[Literal["warn", "break"]] + """warn: log a warning, break: raise a ``NeedsConstraintFailed`` exception""" + style: list[str] + """How to style the rendered need.""" + force_style: bool + """If True, append styles to existing styles, else replace existing styles.""" + + @dataclass class NeedsSphinxConfig: """A wrapper around the Sphinx configuration, @@ -70,6 +87,8 @@ def __init__(self, config: _SphinxConfig) -> None: super().__setattr__("_config", config) def __getattribute__(self, name: str) -> Any: + if name.startswith("__"): + return super().__getattribute__(name) return getattr(super().__getattribute__("_config"), f"needs_{name}") def __setattr__(self, name: str, value: Any) -> None: @@ -214,12 +233,19 @@ def __setattr__(self, name: str, value: Any) -> None: report_template: str = field(default="", metadata={"rebuild": "html", "types": (str,)}) """path to needs_report_template file which is based on the conf.py directory.""" - # add constraints option - constraints: dict[str, dict[str, Any]] = field(default_factory=dict, metadata={"rebuild": "html", "types": (dict,)}) - constraint_failed_options: dict[str, dict[str, Any]] = field( + constraints: dict[str, dict[str, str]] = field(default_factory=dict, metadata={"rebuild": "html", "types": (dict,)}) + """Mapping of constraint name, to check name, to filter string. + There are also some special keys for a constraint: + + - severity: The severity of the constraint. This is used to determine what to do if the constraint is not fulfilled. + - error_message: A help text for the constraint, can include Jinja2 variables. + """ + constraint_failed_options: dict[str, ConstraintFailedType] = field( default_factory=dict, metadata={"rebuild": "html", "types": (dict,)} ) + """Mapping of constraint severity to what to do if a constraint is not fulfilled.""" constraints_failed_color: str = field(default="", metadata={"rebuild": "html", "types": (str,)}) + """DEPRECATED: Use constraint_failed_options instead.""" # add variants option variants: dict[str, str] = field(default_factory=dict, metadata={"rebuild": "html", "types": (dict,)}) @@ -230,6 +256,9 @@ def __setattr__(self, name: str, value: Any) -> None: """Jinja context for rendering templates""" debug_measurement: bool = field(default=False, metadata={"rebuild": "html", "types": (bool,)}) + # add config for needs_id_builder + build_json_per_id: bool = field(default=False, metadata={"rebuild": "html", "types": (bool,)}) + build_json_per_id_path: str = field(default="needs_id", metadata={"rebuild": "html", "types": (str,)}) @classmethod def add_config_values(cls, app: Sphinx) -> None: diff --git a/sphinx_needs/data.py b/sphinx_needs/data.py index 88706c59b..9fa8d44f2 100644 --- a/sphinx_needs/data.py +++ b/sphinx_needs/data.py @@ -3,7 +3,7 @@ """ from __future__ import annotations -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING try: from typing import Literal, TypedDict @@ -30,22 +30,6 @@ class NeedsFilterType(TypedDict): amount: int -class NeedsWorkflowType(TypedDict): - """ - Used to store workflow status information for already executed tasks. - Some tasks like backlink_creation need be performed only once. - But most sphinx-events get called several times (for each single document file), - which would also execute our code several times... - """ - - backlink_creation_links: bool - dynamic_values_resolved: bool - links_checked: bool - add_sections: bool - variant_option_resolved: bool - needs_extended: bool - - class NeedsBaseDataType(TypedDict): """A base type for all data.""" @@ -122,9 +106,10 @@ class NeedsInfoType(NeedsBaseDataType): """Hexadecimal color code of the type.""" type_style: str - # Used by needextend is_modified: bool + """Whether the need was modified by needextend.""" modifications: int + """Number of modifications by needextend.""" # parts information parts: dict[str, NeedsPartType] @@ -158,15 +143,20 @@ class NeedsInfoType(NeedsBaseDataType): # back links are all set in process_need_nodes (-> create_back_links) transform # constraints information - # set in process_need_nodes (-> process_constraints) transform constraints: list[str] + """List of constraint names, which are defined for this need.""" + # set in process_need_nodes (-> process_constraints) transform + constraints_results: dict[str, dict[str, bool]] + """Mapping of constraint name, to check name, to result.""" constraints_passed: None | bool - constraints_results: dict[str, dict[str, Any]] + """True if all constraints passed, False if any failed, None if not yet checked.""" + constraints_error: str + """An error message set if any constraint failed, and `error_message` field is set in config.""" # additional source information doctype: str """Type of the document where the need is defined, e.g. '.rst'""" - # set in add_sections transform + # set in analyse_need_locations transform sections: list[str] section_name: str """Simply the first section""" @@ -254,11 +244,20 @@ class NeedsBarType(NeedsBaseDataType): class NeedsExtendType(NeedsBaseDataType): - """Data to modify an existing need.""" + """Data to modify existing need(s).""" filter: None | str + """Single need ID or filter string to select multiple needs.""" modifications: dict[str, str] + """Mapping of field name to new value. + If the field name starts with a ``+``, the new value is appended to the existing value. + If the field name starts with a ``-``, the existing value is cleared (new value is ignored). + """ strict: bool + """If ``filter`` conforms to ``needs_id_regex``, + and is not an existing need ID, + whether to except the build (otherwise log-info message is written). + """ class NeedsFilteredBaseType(NeedsBaseDataType): @@ -432,27 +431,18 @@ def get_or_create_docs(self) -> dict[str, list[str]]: self.env.needs_all_docs = {"all": []} return self.env.needs_all_docs - def get_or_create_workflow(self) -> NeedsWorkflowType: - """Get workflow information. - - This is lazily created and cached in the environment. - """ + @property + def needs_is_post_processed(self) -> bool: + """Whether needs have been post-processed.""" try: - return self.env.needs_workflow + return self.env.needs_is_post_processed except AttributeError: - self.env.needs_workflow = { - "backlink_creation_links": False, - "dynamic_values_resolved": False, - "links_checked": False, - "add_sections": False, - "variant_option_resolved": False, - "needs_extended": False, - } - # TODO use needs_config here - for link_type in self.env.app.config.needs_extra_links: - self.env.needs_workflow["backlink_creation_{}".format(link_type["option"])] = False - - return self.env.needs_workflow # type: ignore[return-value] + self.env.needs_is_post_processed = False + return self.env.needs_is_post_processed + + @needs_is_post_processed.setter + def needs_is_post_processed(self, value: bool) -> None: + self.env.needs_is_post_processed = value def get_or_create_services(self) -> ServiceManager: """Get information about services. diff --git a/sphinx_needs/debug.py b/sphinx_needs/debug.py index b340510bf..253bd5725 100644 --- a/sphinx_needs/debug.py +++ b/sphinx_needs/debug.py @@ -50,7 +50,6 @@ def my_cool_function(a, b,c ): :param category: Name of a category, which helps to cluster the measured functions. :param source: Should be "internal" or "user". Used to easily structure function written by user. :param name: Name to use for the measured. If not given, the function name is used. - :param func: Can contain a func, which shall get decorated. Not used if ``measure_time`` is used as decorator. """ def inner(func: T) -> T: diff --git a/sphinx_needs/diagrams_common.py b/sphinx_needs/diagrams_common.py index 243f17533..57167d310 100644 --- a/sphinx_needs/diagrams_common.py +++ b/sphinx_needs/diagrams_common.py @@ -18,7 +18,7 @@ from sphinx_needs.data import NeedsFilteredBaseType, NeedsPartsInfoType from sphinx_needs.errors import NoUri from sphinx_needs.logging import get_logger -from sphinx_needs.utils import get_scale, split_link_types, unwrap +from sphinx_needs.utils import get_scale, split_link_types try: from typing import TypedDict @@ -169,7 +169,7 @@ def calculate_link(app: Sphinx, need_info: NeedsPartsInfoType, _fromdocname: str :param fromdocname: :return: """ - builder = unwrap(app.builder) + builder = app.builder try: if need_info["is_external"]: assert need_info["external_url"] is not None, "external_url must be set for external needs" diff --git a/sphinx_needs/directives/need.py b/sphinx_needs/directives/need.py index 1bbb55fc6..2636f403a 100644 --- a/sphinx_needs/directives/need.py +++ b/sphinx_needs/directives/need.py @@ -14,10 +14,14 @@ from sphinx_needs.api import add_need from sphinx_needs.api.exceptions import NeedsInvalidException from sphinx_needs.config import NEEDS_CONFIG, NeedsSphinxConfig -from sphinx_needs.data import SphinxNeedsData +from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.debug import measure_time from sphinx_needs.defaults import NEED_DEFAULT_OPTIONS -from sphinx_needs.directives.needextend import process_needextend +from sphinx_needs.directives.needextend import ( + Needextend, + extend_needs_data, + remove_needextend_node, +) from sphinx_needs.functions import ( find_and_replace_node_content, resolve_dynamic_values, @@ -28,7 +32,7 @@ from sphinx_needs.logging import get_logger from sphinx_needs.need_constraints import process_constraints from sphinx_needs.nodes import Need -from sphinx_needs.utils import add_doc, profile, unwrap +from sphinx_needs.utils import add_doc, profile logger = get_logger(__name__) @@ -285,14 +289,22 @@ def purge_needs(app: Sphinx, env: BuildEnvironment, docname: str) -> None: del needs[need_id] -def add_sections(app: Sphinx, doctree: nodes.document) -> None: - """Add section titles to the needs as additional attributes that can - be used in tables and filters""" - builder = unwrap(app.builder) - env = unwrap(builder.env) +def analyse_need_locations(app: Sphinx, doctree: nodes.document) -> None: + """Determine the location of each need in the doctree, + relative to its parent section(s) and need(s). + + This data is added to the need's data stored in the Sphinx environment, + so that it can be used in tables and filters. + + Once this data is determined, any hidden needs + (i.e. ones that should not be rendered in the output) + are removed from the doctree. + """ + env = app.env needs = SphinxNeedsData(env).get_or_create_needs() + hidden_needs: List[Need] = [] for need_node in doctree.findall(Need): need_id = need_node["refid"] need_info = needs[need_id] @@ -329,6 +341,15 @@ def add_sections(app: Sphinx, doctree: nodes.document) -> None: need_info["parent_needs"] = parent_needs need_info["parent_need"] = parent_needs[0] + if need_node.get("hidden"): + hidden_needs.append(need_node) + + # now we have gathered all the information we need, + # we can remove the hidden needs from the doctree + for need_node in hidden_needs: + if need_node.parent is not None: + need_node.parent.remove(need_node) # type: ignore[attr-defined] + def previous_sibling(node: nodes.Node) -> Optional[nodes.Node]: """Return preceding sibling node or ``None``.""" @@ -345,11 +366,6 @@ def process_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) - """ Event handler to add title meta data (status, tags, links, ...) information to the Need node. Also processes constraints. - - :param app: - :param doctree: - :param fromdocname: - :return: """ needs_config = NeedsSphinxConfig(app.config) if not needs_config.include_needs: @@ -358,50 +374,27 @@ def process_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) - node.parent.remove(node) # type: ignore return - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env + needs_data = SphinxNeedsData(env) + needs = needs_data.get_or_create_needs() # If no needs were defined, we do not need to do anything - if not hasattr(env, "needs_all_needs"): + if not needs: return - # Call dynamic functions and replace related node data with their return values - resolve_dynamic_values(env) - - # Apply variant handling on options and replace its values with their return values - resolve_variants_options(env) + if not needs_data.needs_is_post_processed: + resolve_dynamic_values(needs, app) + resolve_variants_options(needs, needs_config, app.builder.tags.tags) + check_links(needs, needs_config) + create_back_links(needs, needs_config) + process_constraints(needs, needs_config) + extend_needs_data(needs, needs_data.get_or_create_extends(), needs_config) + needs_data.needs_is_post_processed = True - # check if we have dead links - check_links(env) + for extend_node in doctree.findall(Needextend): + remove_needextend_node(extend_node) - # Create back links of common links and extra links - for links in needs_config.extra_links: - create_back_links(env, links["option"]) - - """ - The output of this phase is a doctree for each source file; that is a tree of docutils nodes. - - https://www.sphinx-doc.org/en/master/extdev/index.html - - """ - needs = SphinxNeedsData(env).get_or_create_needs() - - # Used to store needs in the docs, which are needed again later - found_needs_nodes = [] - for node_need in doctree.findall(Need): - if node_need.get("hidden"): - continue - need_id = node_need.attributes["ids"][0] - found_needs_nodes.append(node_need) - need_data = needs[need_id] - - process_constraints(app, need_data) - - # We call process_needextend here by our own, so that we are able - # to give print_need_nodes the already found need_nodes. - process_needextend(app, doctree, fromdocname) - - print_need_nodes(app, doctree, fromdocname, found_needs_nodes) + print_need_nodes(app, doctree, fromdocname, list(doctree.findall(Need))) @profile("NEED_PRINT") @@ -414,8 +407,7 @@ def print_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str, fou :param fromdocname: :return: """ - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env needs = SphinxNeedsData(env).get_or_create_needs() # We try to avoid findall as much as possibles. so we reuse the already found need nodes in the current document. @@ -433,19 +425,14 @@ def print_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str, fou build_need(layout, node_need, app, fromdocname=fromdocname) -def check_links(env: BuildEnvironment) -> None: - """ - Checks if set links are valid or are dead (referenced need does not exist.) - :param env: Sphinx environment - :return: - """ - data = SphinxNeedsData(env) - workflow = data.get_or_create_workflow() - if workflow["links_checked"]: - return +def check_links(needs: Dict[str, NeedsInfoType], config: NeedsSphinxConfig) -> None: + """Checks if set links are valid or are dead (referenced need does not exist.) - needs = data.get_or_create_needs() - extra_links = getattr(env.config, "needs_extra_links", []) + For needs with dead links, an extra ``has_dead_links`` field is added and, + if the link is not allowed to be dead, + the ``has_forbidden_dead_links`` field is also added. + """ + extra_links = config.extra_links for need in needs.values(): for link_type in extra_links: dead_links_allowed = link_type.get("allow_dead_links", False) @@ -466,45 +453,35 @@ def check_links(env: BuildEnvironment) -> None: need["has_forbidden_dead_links"] = True break # One found dead link is enough - # Finally set a flag so that this function gets not executed several times - workflow["links_checked"] = True - -def create_back_links(env: BuildEnvironment, option: str) -> None: - """ - Create back-links in all found needs. - But do this only once, as all needs are already collected and this sorting is for all - needs and not only for the ones of the current document. +def create_back_links(needs: Dict[str, NeedsInfoType], config: NeedsSphinxConfig) -> None: + """Create back-links in all found needs. - :param env: sphinx environment + These are fields for each link type, ``_back``, + which contain a list of all IDs of needs that link to the current need. """ - data = SphinxNeedsData(env) - workflow = data.get_or_create_workflow() - option_back = f"{option}_back" - if workflow[f"backlink_creation_{option}"]: # type: ignore[literal-required] - return - - needs = data.get_or_create_needs() - for key, need in needs.items(): - need_link_value = [need[option]] if isinstance(need[option], str) else need[option] # type: ignore[literal-required] - for link in need_link_value: - link_main = link.split(".")[0] - try: - link_part = link.split(".")[1] - except IndexError: - link_part = None + for links in config.extra_links: + option = links["option"] + option_back = f"{option}_back" - if link_main in needs: - if key not in needs[link_main][option_back]: # type: ignore[literal-required] - needs[link_main][option_back].append(key) # type: ignore[literal-required] + for key, need in needs.items(): + need_link_value = [need[option]] if isinstance(need[option], str) else need[option] # type: ignore[literal-required] + for link in need_link_value: + link_main = link.split(".")[0] + try: + link_part = link.split(".")[1] + except IndexError: + link_part = None - # Handling of links to need_parts inside a need - if link_part and link_part in needs[link_main]["parts"]: - if option_back not in needs[link_main]["parts"][link_part].keys(): - needs[link_main]["parts"][link_part][option_back] = [] # type: ignore[literal-required] - needs[link_main]["parts"][link_part][option_back].append(key) # type: ignore[literal-required] + if link_main in needs: + if key not in needs[link_main][option_back]: # type: ignore[literal-required] + needs[link_main][option_back].append(key) # type: ignore[literal-required] - workflow[f"backlink_creation_{option}"] = True # type: ignore[literal-required] + # Handling of links to need_parts inside a need + if link_part and link_part in needs[link_main]["parts"]: + if option_back not in needs[link_main]["parts"][link_part].keys(): + needs[link_main]["parts"][link_part][option_back] = [] # type: ignore[literal-required] + needs[link_main]["parts"][link_part][option_back].append(key) # type: ignore[literal-required] def _fix_list_dyn_func(list: List[str]) -> List[str]: @@ -544,15 +521,6 @@ def _fix_list_dyn_func(list: List[str]) -> List[str]: return new_list -def remove_hidden_needs(app: Sphinx, doctree: nodes.document, fromdocname: str) -> None: - """Remove hidden needs from the doctree, before it is rendered.""" - if fromdocname not in SphinxNeedsData(app.env).get_or_create_docs().get("all", []): - return - for node_need in list(doctree.findall(Need)): - if node_need.get("hidden"): - node_need.parent.remove(node_need) # type: ignore - - ##################### # Visitor functions # ##################### diff --git a/sphinx_needs/directives/needbar.py b/sphinx_needs/directives/needbar.py index 777b07525..1ddd5d572 100644 --- a/sphinx_needs/directives/needbar.py +++ b/sphinx_needs/directives/needbar.py @@ -10,7 +10,7 @@ from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import SphinxNeedsData from sphinx_needs.filter_common import FilterBase, filter_needs, prepare_need_list -from sphinx_needs.utils import add_doc, save_matplotlib_figure, unwrap +from sphinx_needs.utils import add_doc, save_matplotlib_figure if not os.environ.get("DISPLAY"): matplotlib.use("Agg") @@ -168,8 +168,7 @@ def run(self) -> Sequence[nodes.Node]: # 9. final storage # 10. cleanup matplotlib def process_needbar(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env needs_config = NeedsSphinxConfig(env.config) # NEEDFLOW @@ -272,7 +271,7 @@ def process_needbar(app: Sphinx, doctree: nodes.document, fromdocname: str, foun if element.isdigit(): line_number.append(float(element)) else: - result = len(filter_needs(app, need_list, element)) + result = len(filter_needs(need_list, needs_config, element)) line_number.append(float(result)) local_data_number.append(line_number) diff --git a/sphinx_needs/directives/needextend.py b/sphinx_needs/directives/needextend.py index 1b2c7f75d..fdfc3789a 100644 --- a/sphinx_needs/directives/needextend.py +++ b/sphinx_needs/directives/needextend.py @@ -7,15 +7,14 @@ from docutils import nodes from docutils.parsers.rst import directives -from sphinx.application import Sphinx from sphinx.util.docutils import SphinxDirective from sphinx_needs.api.exceptions import NeedsInvalidFilter from sphinx_needs.config import NeedsSphinxConfig -from sphinx_needs.data import SphinxNeedsData +from sphinx_needs.data import NeedsExtendType, NeedsInfoType, SphinxNeedsData from sphinx_needs.filter_common import filter_needs from sphinx_needs.logging import get_logger -from sphinx_needs.utils import add_doc, unwrap +from sphinx_needs.utils import add_doc logger = get_logger(__name__) @@ -71,136 +70,116 @@ def run(self) -> Sequence[nodes.Node]: return [targetnode, Needextend("")] -def process_needextend(app: Sphinx, doctree: nodes.document, fromdocname: str) -> None: - """ - Perform all modifications on needs - """ - builder = unwrap(app.builder) - env = unwrap(builder.env) - needs_config = NeedsSphinxConfig(env.config) - data = SphinxNeedsData(env) - workflow = data.get_or_create_workflow() - - if not workflow["needs_extended"]: - workflow["needs_extended"] = True - - list_names = ( - ["tags", "links"] - + [x["option"] for x in needs_config.extra_links] - + [f"{x['option']}_back" for x in needs_config.extra_links] - ) # back-links (incoming) - link_names = [x["option"] for x in needs_config.extra_links] - - all_needs = data.get_or_create_needs() - - for current_needextend in data.get_or_create_extends().values(): - # Check if filter is just a need-id. - # In this case create the needed filter string - need_filter = current_needextend["filter"] - if need_filter in all_needs: - need_filter = f'id == "{need_filter}"' - # If it looks like a need id, but we haven't found one, raise an exception - elif need_filter is not None and re.fullmatch(needs_config.id_regex, need_filter): - error = f"Provided id {need_filter} for needextend does not exist." - if current_needextend["strict"]: - raise NeedsInvalidFilter(error) - else: - logger.info(error) - continue +def extend_needs_data( + all_needs: Dict[str, NeedsInfoType], extends: Dict[str, NeedsExtendType], needs_config: NeedsSphinxConfig +) -> None: + """Use data gathered from needextend directives to modify fields of existing needs.""" + + list_values = ( + ["tags", "links"] + + [x["option"] for x in needs_config.extra_links] + + [f"{x['option']}_back" for x in needs_config.extra_links] + ) # back-links (incoming) + link_names = [x["option"] for x in needs_config.extra_links] + + for current_needextend in extends.values(): + need_filter = current_needextend["filter"] + if need_filter in all_needs: + # a single known ID + found_needs = [all_needs[need_filter]] + elif need_filter is not None and re.fullmatch(needs_config.id_regex, need_filter): + # an unknown ID + error = f"Provided id {need_filter} for needextend does not exist." + if current_needextend["strict"]: + raise NeedsInvalidFilter(error) + else: + logger.info(error) + continue + else: + # a filter string try: - found_needs = filter_needs(app, all_needs.values(), need_filter) + found_needs = filter_needs(all_needs.values(), needs_config, need_filter) except NeedsInvalidFilter as e: raise NeedsInvalidFilter( f"Filter not valid for needextend on page {current_needextend['docname']}:\n{e}" ) - for found_need in found_needs: - # Work in the stored needs, not on the search result - need = all_needs[found_need["id"]] - need["is_modified"] = True - need["modifications"] += 1 - - for option, value in current_needextend["modifications"].items(): - if option.startswith("+"): - option_name = option[1:] - - # If we need to handle a list - if option_name in list_names: - for link in re.split(";|,", value): - # Remove whitespaces - link = link.strip() - if link not in need[option_name]: - need[option_name].append(link) - - # If we manipulate links, we need to set all the reference in the target need - # under e.g. links_back - if option_name in link_names: - for ref_need in re.split(";|,", value): - # Remove whitespaces - ref_need = ref_need.strip() - if found_need["id"] not in all_needs[ref_need][f"{option_name}_back"]: - all_needs[ref_need][f"{option_name}_back"] += [found_need["id"]] - - # else it must be a normal string - else: + for found_need in found_needs: + # Work in the stored needs, not on the search result + need = all_needs[found_need["id"]] + need["is_modified"] = True + need["modifications"] += 1 + + for option, value in current_needextend["modifications"].items(): + if option.startswith("+"): + option_name = option[1:] + if option_name in link_names: + # If we add links, then add all corresponding back links + for ref_need in [i.strip() for i in re.split(";|,", value)]: + if ref_need not in all_needs: + logger.warning( + f"Provided link id {ref_need} for needextend does not exist. [needs]", + type="needs", + location=(current_needextend["docname"], current_needextend["lineno"]), + ) + continue + if ref_need not in need[option_name]: + need[option_name].append(ref_need) + if found_need["id"] not in all_needs[ref_need][f"{option_name}_back"]: + all_needs[ref_need][f"{option_name}_back"] += [found_need["id"]] + elif option_name in list_values: + for item in [i.strip() for i in re.split(";|,", value)]: + if item not in need[option_name]: + need[option_name].append(item) + else: + if need[option_name]: # If content is already stored, we need to add some whitespace - if need[option_name]: - need[option_name] += " " - need[option_name] += value - elif option.startswith("-"): - option_name = option[1:] - if option_name in list_names: - old_content = need[option_name] # Save it, as it may be need to identify referenced needs - need[option_name] = [] - - # If we manipulate links, we need to delete the reference in the target need as well - if option_name in link_names: - for ref_need in old_content: # There may be several links - all_needs[ref_need][f"{option_name}_back"].remove(found_need["id"]) - - else: - need[option_name] = "" + need[option_name] += " " + need[option_name] += value + + elif option.startswith("-"): + option_name = option[1:] + if option_name in link_names: + # If we remove links, then remove all corresponding back links + for ref_need in (i for i in need[option_name] if i in all_needs): + all_needs[ref_need][f"{option_name}_back"].remove(found_need["id"]) + need[option_name] = [] + if option_name in list_values: + need[option_name] = [] else: - if option in list_names: - old_content = need[option].copy() - - need[option] = [] - for link in re.split(";|,", value): - # Remove whitespaces - link = link.strip() - if link not in need[option]: - need[option].append(link) - - # If add new links also as "link_s_back" to the referenced need. - if option in link_names: - # Remove old links - for ref_need in old_content: # There may be several links - all_needs[ref_need][f"{option}_back"].remove(found_need["id"]) - - # Add new links - for ref_need in need[option]: # There may be several links - if found_need["id"] not in all_needs[ref_need][f"{option}_back"]: - all_needs[ref_need][f"{option}_back"] += [found_need["id"]] - - else: - need[option] = value - - for node in doctree.findall(Needextend): - # No printouts for needextend - removed_needextend_node(node) + need[option_name] = "" + else: + if option in link_names: + # If we change links, then modify all corresponding back links + for ref_need in (i for i in need[option] if i in all_needs): + all_needs[ref_need][f"{option}_back"].remove(found_need["id"]) + need[option] = [] + for ref_need in [i.strip() for i in re.split(";|,", value)]: + if ref_need not in all_needs: + logger.warning( + f"Provided link id {ref_need} for needextend does not exist. [needs]", + type="needs", + location=(current_needextend["docname"], current_needextend["lineno"]), + ) + continue + need[option].append(ref_need) + for ref_need in need[option]: + if found_need["id"] not in all_needs[ref_need][f"{option}_back"]: + all_needs[ref_need][f"{option}_back"] += [found_need["id"]] + elif option in list_values: + need[option] = [i.strip() for i in re.split(";|,", value)] + else: + need[option] = value -def removed_needextend_node(node: Needextend) -> None: +def remove_needextend_node(node: Needextend) -> None: """ - # Remove needextend from docutils node-tree, so that no output gets generated for it. - # Ok, this is really dirty. - # If we replace a node, docutils checks, if it will not lose any attributes. - # But this is here the case, because we are using the attribute "ids" of a node. - # However, I do not understand, why losing an attribute is such a big deal, so we delete everything - # before docutils claims about it. - - :param node: - :return: + Remove needextend from docutils node-tree, so that no output gets generated for it. + Ok, this is really dirty. + If we replace a node, docutils checks, if it will not lose any attributes. + But this is here the case, because we are using the attribute "ids" of a node. + However, I do not understand, why losing an attribute is such a big deal, so we delete everything + before docutils claims about it. """ for att in ("ids", "names", "classes", "dupnames"): diff --git a/sphinx_needs/directives/needextract.py b/sphinx_needs/directives/needextract.py index d4cc0406e..dc397a5a5 100644 --- a/sphinx_needs/directives/needextract.py +++ b/sphinx_needs/directives/needextract.py @@ -19,7 +19,7 @@ ) from sphinx_needs.filter_common import FilterBase, process_filters from sphinx_needs.layout import create_need -from sphinx_needs.utils import add_doc, unwrap +from sphinx_needs.utils import add_doc class Needextract(nodes.General, nodes.Element): @@ -75,7 +75,7 @@ def process_needextract( """ Replace all needextract nodes with a list of the collected needs. """ - env = unwrap(app.env) + env = app.env needs_config = NeedsSphinxConfig(app.config) for node in found_nodes: diff --git a/sphinx_needs/directives/needfilter.py b/sphinx_needs/directives/needfilter.py index ef196bb73..d1d6326f0 100644 --- a/sphinx_needs/directives/needfilter.py +++ b/sphinx_needs/directives/needfilter.py @@ -12,7 +12,7 @@ from sphinx_needs.data import SphinxNeedsData from sphinx_needs.diagrams_common import create_legend from sphinx_needs.filter_common import FilterBase, process_filters -from sphinx_needs.utils import add_doc, row_col_maker, unwrap +from sphinx_needs.utils import add_doc, row_col_maker class Needfilter(nodes.General, nodes.Element): @@ -74,8 +74,8 @@ def process_needfilters( ) -> None: # Replace all needlist nodes with a list of the collected needs. # Augment each need with a backlink to the original location. - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env needs_config = NeedsSphinxConfig(env.config) all_needs = SphinxNeedsData(env).get_or_create_needs() diff --git a/sphinx_needs/directives/needflow.py b/sphinx_needs/directives/needflow.py index 19315e33c..e586b4d70 100644 --- a/sphinx_needs/directives/needflow.py +++ b/sphinx_needs/directives/needflow.py @@ -21,7 +21,7 @@ from sphinx_needs.diagrams_common import calculate_link, create_legend from sphinx_needs.filter_common import FilterBase, filter_single_need, process_filters from sphinx_needs.logging import get_logger -from sphinx_needs.utils import add_doc, get_scale, split_link_types, unwrap +from sphinx_needs.utils import add_doc, get_scale, split_link_types logger = get_logger(__name__) @@ -130,7 +130,9 @@ def get_need_node_rep_for_plantuml( # We set # later, as the user may not have given a color and the node must get highlighted node_colors.append(need_info["type_color"].replace("#", "")) - if current_needflow["highlight"] and filter_single_need(app, need_info, current_needflow["highlight"], all_needs): + if current_needflow["highlight"] and filter_single_need( + need_info, needs_config, current_needflow["highlight"], all_needs + ): node_colors.append("line:FF0000") # need parts style use default "rectangle" @@ -271,7 +273,7 @@ def cal_needs_node( def process_needflow(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: # Replace all needflow nodes with a list of the collected needs. # Augment each need with a backlink to the original location. - env = unwrap(app.env) + env = app.env needs_config = NeedsSphinxConfig(app.config) env_data = SphinxNeedsData(env) all_needs = env_data.get_or_create_needs() diff --git a/sphinx_needs/directives/needgantt.py b/sphinx_needs/directives/needgantt.py index 05a66862b..ec6dc182d 100644 --- a/sphinx_needs/directives/needgantt.py +++ b/sphinx_needs/directives/needgantt.py @@ -135,7 +135,7 @@ def get_link_type_option(self, name: str, default: str = "") -> List[str]: def process_needgantt(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: # Replace all needgantt nodes with a list of the collected needs. - env = app.builder.env + env = app.env needs_config = NeedsSphinxConfig(app.config) # link_types = needs_config.extra_links @@ -214,7 +214,7 @@ def process_needgantt(app: Sphinx, doctree: nodes.document, fromdocname: str, fo complete = None if current_needgantt["milestone_filter"]: - is_milestone = filter_single_need(app, need, current_needgantt["milestone_filter"]) + is_milestone = filter_single_need(need, needs_config, current_needgantt["milestone_filter"]) else: is_milestone = False @@ -259,7 +259,7 @@ def process_needgantt(app: Sphinx, doctree: nodes.document, fromdocname: str, fo puml_node["uml"] += "\n' Constraints definition \n\n" for need in found_needs: if current_needgantt["milestone_filter"]: - is_milestone = filter_single_need(app, need, current_needgantt["milestone_filter"]) + is_milestone = filter_single_need(need, needs_config, current_needgantt["milestone_filter"]) else: is_milestone = False for con_type in ("starts_with_links", "starts_after_links", "ends_with_links"): diff --git a/sphinx_needs/directives/needimport.py b/sphinx_needs/directives/needimport.py index cdccd1409..299d718d4 100644 --- a/sphinx_needs/directives/needimport.py +++ b/sphinx_needs/directives/needimport.py @@ -123,6 +123,7 @@ def run(self) -> Sequence[nodes.Node]: if version not in needs_import_list["versions"].keys(): raise VersionNotFound(f"Version {version} not found in needs import file {correct_need_import_path}") + needs_config = NeedsSphinxConfig(self.config) # TODO this is not exactly NeedsInfoType, because the export removes/adds some keys needs_list: Dict[str, NeedsInfoType] = needs_import_list["versions"][version]["needs"] @@ -138,7 +139,7 @@ def run(self) -> Sequence[nodes.Node]: # "content" is the sphinx internal name for this kind of information filter_context["content"] = need["description"] # type: ignore[typeddict-item] try: - if filter_single_need(self.env.app, filter_context, filter_string): + if filter_single_need(filter_context, needs_config, filter_string): needs_list_filtered[key] = need except Exception as e: logger.warning( @@ -152,7 +153,7 @@ def run(self) -> Sequence[nodes.Node]: needs_list = needs_list_filtered # If we need to set an id prefix, we also need to manipulate all used ids in the imported data. - extra_links = NeedsSphinxConfig(self.config).extra_links + extra_links = needs_config.extra_links if id_prefix: for need in needs_list.values(): for id in needs_list: diff --git a/sphinx_needs/directives/needlist.py b/sphinx_needs/directives/needlist.py index f35f4a904..ea8979560 100644 --- a/sphinx_needs/directives/needlist.py +++ b/sphinx_needs/directives/needlist.py @@ -15,7 +15,7 @@ used_filter_paragraph, ) from sphinx_needs.filter_common import FilterBase, process_filters -from sphinx_needs.utils import add_doc, check_and_calc_base_url_rel_path, unwrap +from sphinx_needs.utils import add_doc, check_and_calc_base_url_rel_path class Needlist(nodes.General, nodes.Element): @@ -64,8 +64,8 @@ def process_needlist(app: Sphinx, doctree: nodes.document, fromdocname: str, fou Replace all needlist nodes with a list of the collected needs. Augment each need with a backlink to the original location. """ - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env include_needs = NeedsSphinxConfig(env.config).include_needs # for node in doctree.findall(Needlist): diff --git a/sphinx_needs/directives/needpie.py b/sphinx_needs/directives/needpie.py index 1dcb2982a..09bc3c70c 100644 --- a/sphinx_needs/directives/needpie.py +++ b/sphinx_needs/directives/needpie.py @@ -1,4 +1,3 @@ -import copy import os from typing import Iterable, List, Sequence @@ -24,7 +23,6 @@ add_doc, check_and_get_external_filter_func, save_matplotlib_figure, - unwrap, ) logger = get_logger(__name__) @@ -111,12 +109,12 @@ def run(self) -> Sequence[nodes.Node]: @measure_time("needpie") def process_needpie(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env needs_data = SphinxNeedsData(env) + needs_config = NeedsSphinxConfig(env.config) # NEEDFLOW - include_needs = NeedsSphinxConfig(env.config).include_needs + include_needs = needs_config.include_needs # for node in doctree.findall(Needpie): for node in found_nodes: if not include_needs: @@ -149,7 +147,7 @@ def process_needpie(app: Sphinx, doctree: nodes.document, fromdocname: str, foun if line.isdigit(): sizes.append(abs(float(line))) else: - result = len(filter_needs(app, need_list, line)) + result = len(filter_needs(need_list, needs_config, line)) sizes.append(result) elif current_needpie["filter_func"] and not content: try: @@ -158,7 +156,7 @@ def process_needpie(app: Sphinx, doctree: nodes.document, fromdocname: str, foun # execute filter_func code # Provides only a copy of needs to avoid data manipulations. context = { - "needs": copy.deepcopy(need_list), + "needs": need_list, "results": [], } args = [] diff --git a/sphinx_needs/directives/needsequence.py b/sphinx_needs/directives/needsequence.py index c98e885c8..63ccd3aad 100644 --- a/sphinx_needs/directives/needsequence.py +++ b/sphinx_needs/directives/needsequence.py @@ -21,7 +21,7 @@ ) from sphinx_needs.filter_common import FilterBase from sphinx_needs.logging import get_logger -from sphinx_needs.utils import add_doc, unwrap +from sphinx_needs.utils import add_doc logger = get_logger(__name__) @@ -76,8 +76,7 @@ def process_needsequence( app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element] ) -> None: # Replace all needsequence nodes with a list of the collected needs. - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env needs_data = SphinxNeedsData(env) all_needs_dict = needs_data.get_or_create_needs() @@ -260,7 +259,9 @@ def get_message_needs( if filter: from sphinx_needs.filter_common import filter_single_need - if not filter_single_need(app, all_needs_dict[rec_id], filter, needs=all_needs_dict.values()): + if not filter_single_need( + all_needs_dict[rec_id], NeedsSphinxConfig(app.config), filter, needs=all_needs_dict.values() + ): continue rec_data = {"id": rec_id, "title": all_needs_dict[rec_id]["title"], "messages": []} diff --git a/sphinx_needs/directives/needservice.py b/sphinx_needs/directives/needservice.py index 072a27a16..2adb2cf64 100644 --- a/sphinx_needs/directives/needservice.py +++ b/sphinx_needs/directives/needservice.py @@ -12,7 +12,7 @@ from sphinx_needs.directives.need import NeedDirective from sphinx_needs.logging import get_logger from sphinx_needs.services.base import BaseService -from sphinx_needs.utils import add_doc, unwrap +from sphinx_needs.utils import add_doc class Needservice(nodes.General, nodes.Element): @@ -58,7 +58,8 @@ def run(self) -> Sequence[nodes.Node]: needs_services: Dict[str, BaseService] = getattr(app, "needs_services", {}) service_name = self.arguments[0] - service = unwrap(needs_services.get(service_name)) + service = needs_services.get(service_name) + assert service is not None section = [] if "debug" not in self.options: diff --git a/sphinx_needs/directives/needtable.py b/sphinx_needs/directives/needtable.py index 304ee48ce..7cf4faf06 100644 --- a/sphinx_needs/directives/needtable.py +++ b/sphinx_needs/directives/needtable.py @@ -17,7 +17,7 @@ ) from sphinx_needs.filter_common import FilterBase, process_filters from sphinx_needs.functions.functions import check_and_get_content -from sphinx_needs.utils import add_doc, profile, row_col_maker, unwrap +from sphinx_needs.utils import add_doc, profile, row_col_maker class Needtable(nodes.General, nodes.Element): @@ -117,14 +117,8 @@ def process_needtables( ) -> None: """ Replace all needtables nodes with a table of filtered nodes. - - :param app: - :param doctree: - :param fromdocname: - :return: """ - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env needs_config = NeedsSphinxConfig(app.config) needs_data = SphinxNeedsData(env) diff --git a/sphinx_needs/directives/needuml.py b/sphinx_needs/directives/needuml.py index 30e3b96a5..bd679cdbb 100644 --- a/sphinx_needs/directives/needuml.py +++ b/sphinx_needs/directives/needuml.py @@ -350,8 +350,9 @@ def filter(self, filter_string): """ Return a list of found needs that pass the given filter string. """ + needs_config = NeedsSphinxConfig(self.app.config) - return filter_needs(self.app, list(self.needs.values()), filter_string=filter_string) + return filter_needs(list(self.needs.values()), needs_config, filter_string=filter_string) def imports(self, *args): if not self.parent_need_id: @@ -405,7 +406,7 @@ def is_element_of_need(node: nodes.Element) -> str: @measure_time("needuml") def process_needuml(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: - env = app.builder.env + env = app.env # for node in doctree.findall(Needuml): for node in found_nodes: diff --git a/sphinx_needs/environment.py b/sphinx_needs/environment.py index 09cb7c9a2..2b78a170f 100644 --- a/sphinx_needs/environment.py +++ b/sphinx_needs/environment.py @@ -9,7 +9,7 @@ from sphinx.util.osutil import copyfile from sphinx_needs.config import NeedsSphinxConfig -from sphinx_needs.utils import logger, unwrap +from sphinx_needs.utils import logger IMAGE_DIR_NAME = "_static" @@ -26,7 +26,7 @@ def safe_add_file(filename: Path, app: Sphinx) -> None: :param app: app object :return: None """ - builder = unwrap(app.builder) + builder = app.builder # Use PurePosixPath, so that the path can be used as "web"-path pure_path = PurePosixPath(filename) static_data_file = PurePosixPath("_static") / pure_path @@ -74,7 +74,7 @@ def _remove_file(file: PurePosixPath, attribute: str) -> None: # Base implementation from sphinxcontrib-images # https://github.com/spinus/sphinxcontrib-images/blob/master/sphinxcontrib/images.py#L203 def install_styles_static_files(app: Sphinx, env: BuildEnvironment) -> None: - builder = unwrap(app.builder) + builder = app.builder # Do not copy static_files for our "needs" builder if builder.name == "needs": return @@ -131,7 +131,7 @@ def install_static_files( files_to_copy: List[Path], message: str, ) -> None: - builder = unwrap(app.builder) + builder = app.builder # Do not copy static_files for our "needs" builder if builder.name == "needs": return @@ -165,7 +165,7 @@ def install_lib_static_files(app: Sphinx, env: BuildEnvironment) -> None: :param env: :return: """ - builder = unwrap(app.builder) + builder = app.builder # Do not copy static_files for our "needs" builder if builder.name == "needs": return @@ -197,7 +197,7 @@ def install_permalink_file(app: Sphinx, env: BuildEnvironment) -> None: :param env: :return: """ - builder = unwrap(app.builder) + builder = app.builder # Do not copy static_files for our "needs" builder if builder.name == "needs": return diff --git a/sphinx_needs/external_needs.py b/sphinx_needs/external_needs.py index 2c3af8c50..f46f7bd1f 100644 --- a/sphinx_needs/external_needs.py +++ b/sphinx_needs/external_needs.py @@ -1,8 +1,9 @@ import json import os +from functools import lru_cache import requests -from jinja2 import Environment +from jinja2 import Environment, Template from requests_file import FileAdapter from sphinx.application import Sphinx from sphinx.environment import BuildEnvironment @@ -17,6 +18,16 @@ log = get_logger(__name__) +@lru_cache(maxsize=20) +def get_target_template(target_url: str) -> Template: + """ + Provides template for target_link style + Can be cached, as the template is always the same for a given target_url + """ + mem_template = Environment().from_string(target_url) + return mem_template + + def load_external_needs(app: Sphinx, env: BuildEnvironment, _docname: str) -> None: needs_config = NeedsSphinxConfig(app.config) for source in needs_config.external_needs: @@ -95,7 +106,7 @@ def load_external_needs(app: Sphinx, env: BuildEnvironment, _docname: str) -> No if target_url: # render jinja content - mem_template = Environment().from_string(target_url) + mem_template = get_target_template(target_url) cal_target_url = mem_template.render(**{"need": need}) need_params["external_url"] = f'{source["base_url"]}/{cal_target_url}' else: diff --git a/sphinx_needs/filter_common.py b/sphinx_needs/filter_common.py index 401ee425d..5bab81c0b 100644 --- a/sphinx_needs/filter_common.py +++ b/sphinx_needs/filter_common.py @@ -4,7 +4,6 @@ """ from __future__ import annotations -import copy import re from types import CodeType from typing import Any, Iterable, TypeVar @@ -103,6 +102,7 @@ def process_filters( :return: list of needs, which passed the filters """ + needs_config = NeedsSphinxConfig(app.config) found_needs: list[NeedsPartsInfoType] sort_key = filter_data["sort_by"] if sort_key: @@ -157,17 +157,17 @@ def process_filters( if status_filter_passed and tags_filter_passed and type_filter_passed: found_needs_by_options.append(need_info) # Get need by filter string - found_needs_by_string = filter_needs(app, all_needs_incl_parts, filter_data["filter"]) + found_needs_by_string = filter_needs(all_needs_incl_parts, needs_config, filter_data["filter"]) # Make an intersection of both lists found_needs = intersection_of_need_results(found_needs_by_options, found_needs_by_string) else: # There is no other config as the one for filter string. # So we only need this result. - found_needs = filter_needs(app, all_needs_incl_parts, filter_data["filter"]) + found_needs = filter_needs(all_needs_incl_parts, needs_config, filter_data["filter"]) else: # Provides only a copy of needs to avoid data manipulations. context = { - "needs": copy.deepcopy(all_needs_incl_parts), + "needs": all_needs_incl_parts, "results": [], } @@ -193,7 +193,7 @@ def process_filters( found_needs = [] # Check if config allow unsafe filters - if NeedsSphinxConfig(app.config).allow_unsafe_filters: + if needs_config.allow_unsafe_filters: found_needs = found_dirty_needs else: # Just take the ids from search result and use the related, but original need @@ -204,8 +204,7 @@ def process_filters( # Store basic filter configuration and result global list. # Needed mainly for exporting the result to needs.json (if builder "needs" is used). - env = app.env - filter_list = SphinxNeedsData(env).get_or_create_filters() + filter_list = SphinxNeedsData(app.env).get_or_create_filters() found_needs_ids = [need["id_complete"] for need in found_needs] filter_list[filter_data["target_id"]] = { @@ -259,8 +258,8 @@ def intersection_of_need_results(list_a: list[T], list_b: list[T]) -> list[T]: @measure_time("filtering") def filter_needs( - app: Sphinx, needs: Iterable[V], + config: NeedsSphinxConfig, filter_string: None | str = "", current_need: NeedsInfoType | None = None, ) -> list[V]: @@ -268,14 +267,13 @@ def filter_needs( Filters given needs based on a given filter string. Returns all needs, which pass the given filter. - :param app: Sphinx application object :param needs: list of needs, which shall be filtered + :param config: NeedsSphinxConfig object :param filter_string: strings, which gets evaluated against each need :param current_need: current need, which uses the filter. :return: list of found needs """ - if not filter_string: return list(needs) @@ -287,7 +285,7 @@ def filter_needs( for filter_need in needs: try: if filter_single_need( - app, filter_need, filter_string, needs, current_need, filter_compiled=filter_compiled + filter_need, config, filter_string, needs, current_need, filter_compiled=filter_compiled ): found_needs.append(filter_need) except Exception as e: @@ -305,8 +303,8 @@ def need_search(*args: Any, **kwargs: Any) -> bool: @measure_time("filtering") def filter_single_need( - app: Sphinx, need: NeedsInfoType, + config: NeedsSphinxConfig, filter_string: str = "", needs: Iterable[NeedsInfoType] | None = None, current_need: NeedsInfoType | None = None, @@ -315,8 +313,8 @@ def filter_single_need( """ Checks if a single need/need_part passes a filter_string - :param app: Sphinx application object - :param current_need: + :param need: the data for a single need + :param config: NeedsSphinxConfig object :param filter_compiled: An already compiled filter_string to safe time :param need: need or need_part :param filter_string: string, which is used as input for eval() @@ -332,7 +330,7 @@ def filter_single_need( filter_context["current_need"] = need # Get needs external filter data and merge to filter_context - filter_context.update(NeedsSphinxConfig(app.config).filter_data) + filter_context.update(config.filter_data) filter_context["search"] = need_search result = False diff --git a/sphinx_needs/functions/common.py b/sphinx_needs/functions/common.py index 29638c123..69d6f4e37 100644 --- a/sphinx_needs/functions/common.py +++ b/sphinx_needs/functions/common.py @@ -11,6 +11,7 @@ from sphinx.application import Sphinx from sphinx_needs.api.exceptions import NeedsInvalidFilter +from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import NeedsInfoType from sphinx_needs.filter_common import filter_needs, filter_single_need from sphinx_needs.utils import logger @@ -151,7 +152,7 @@ def copy( need = needs[need_id] if filter: - result = filter_needs(app, needs.values(), filter, need) + result = filter_needs(needs.values(), NeedsSphinxConfig(app.config), filter, need) if result: need = result[0] @@ -308,6 +309,7 @@ def check_linked_values( :param one_hit: If True, only one linked need must have a positive check :return: result, if all checks are positive """ + needs_config = NeedsSphinxConfig(app.config) links = need["links"] if not isinstance(search_value, list): search_value = [search_value] @@ -316,7 +318,7 @@ def check_linked_values( need = needs[link] if filter_string: try: - if not filter_single_need(app, need, filter_string): + if not filter_single_need(need, needs_config, filter_string): continue except Exception as e: logger.warning(f"CheckLinkedValues: Filter {filter_string} not valid: Error: {e} [needs]", type="needs") @@ -417,6 +419,7 @@ def calc_sum( :return: A float number """ + needs_config = NeedsSphinxConfig(app.config) check_needs = [needs[link] for link in need["links"]] if links_only else needs.values() calculated_sum = 0.0 @@ -424,7 +427,7 @@ def calc_sum( for check_need in check_needs: if filter: try: - if not filter_single_need(app, check_need, filter): + if not filter_single_need(check_need, needs_config, filter): continue except ValueError: pass @@ -506,9 +509,10 @@ def links_from_content( raw_links.append(link[1]) if filter: + needs_config = NeedsSphinxConfig(app.config) filtered_links = [] for link in raw_links: - if link not in filtered_links and filter_single_need(app, needs[link], filter): + if link not in filtered_links and filter_single_need(needs[link], needs_config, filter): filtered_links.append(link) return filtered_links diff --git a/sphinx_needs/functions/functions.py b/sphinx_needs/functions/functions.py index f184bc2da..52a8bb441 100644 --- a/sphinx_needs/functions/functions.py +++ b/sphinx_needs/functions/functions.py @@ -8,7 +8,7 @@ import ast import re -from typing import Any, Callable, Dict, List, Optional, Union +from typing import Any, Callable, Dict, List, Optional, Tuple, Union from docutils import nodes from sphinx.application import Sphinx @@ -16,7 +16,7 @@ from sphinx.errors import SphinxError from sphinx_needs.config import NeedsSphinxConfig -from sphinx_needs.data import SphinxNeedsData +from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.debug import measure_time_func from sphinx_needs.logging import get_logger from sphinx_needs.utils import NEEDS_FUNCTIONS, match_variants # noqa: F401 @@ -25,8 +25,10 @@ unicode = str ast_boolean = ast.NameConstant -# TODO this input args should actually be of type `Need` and `List[Need]`, however `Need` is *currently* untyped. -DynamicFunction = Callable[[Sphinx, Any, Any], Union[str, int, float, List[Union[str, int, float]]]] +# TODO these functions also take optional *args and **kwargs +DynamicFunction = Callable[ + [Sphinx, NeedsInfoType, Dict[str, NeedsInfoType]], Union[str, int, float, List[Union[str, int, float]]] +] def register_func(need_function: DynamicFunction, name: Optional[str] = None) -> None: @@ -56,12 +58,12 @@ def register_func(need_function: DynamicFunction, name: Optional[str] = None) -> NEEDS_FUNCTIONS[func_name] = {"name": func_name, "function": need_function} -def execute_func(env: BuildEnvironment, need, func_string: str): - """ - Executes a given function string. +def execute_func(app: Sphinx, need: NeedsInfoType, func_string: str) -> Any: + """Executes a given function string. + :param env: Sphinx environment :param need: Actual need, which contains the found function string - :param func_string: string of the found function. Without [[ ]] + :param func_string: string of the found function. Without ``[[ ]]`` :return: return value of executed function """ global NEEDS_FUNCTIONS @@ -71,7 +73,7 @@ def execute_func(env: BuildEnvironment, need, func_string: str): raise SphinxError("Unknown dynamic sphinx-needs function: {}. Found in need: {}".format(func_name, need["id"])) func = measure_time_func(NEEDS_FUNCTIONS[func_name]["function"], category="dyn_func", source="user") - func_return = func(env.app, need, SphinxNeedsData(env).get_or_create_needs(), *func_args, **func_kwargs) + func_return = func(app, need, SphinxNeedsData(app.env).get_or_create_needs(), *func_args, **func_kwargs) if not isinstance(func_return, (str, int, float, list, unicode)) and func_return: raise SphinxError( @@ -93,7 +95,7 @@ def execute_func(env: BuildEnvironment, need, func_string: str): func_pattern = re.compile(r"\[\[(.*?)\]\]") # RegEx to detect function strings -def find_and_replace_node_content(node, env: BuildEnvironment, need): +def find_and_replace_node_content(node: nodes.Node, env: BuildEnvironment, need: NeedsInfoType) -> nodes.Node: """ Search inside a given node and its children for nodes of type Text, if found, check if it contains a function string and run/replace it. @@ -109,7 +111,7 @@ def find_and_replace_node_content(node, env: BuildEnvironment, need): except KeyError: # If no refuri is set, we don't need to modify anything. # So stop here and return the untouched node. - return node + return node # type: ignore else: new_text = node func_match = func_pattern.findall(new_text) @@ -125,7 +127,7 @@ def find_and_replace_node_content(node, env: BuildEnvironment, need): func_string = func_string.replace("‘", "'") func_string = func_string.replace("’", "'") - func_return = execute_func(env, need, func_string) + func_return = execute_func(env.app, need, func_string) # This should never happen, but we can not be sure. if isinstance(func_return, list): @@ -142,7 +144,7 @@ def find_and_replace_node_content(node, env: BuildEnvironment, need): node.children = new_children else: node = nodes.Text(new_text) - return node + return node # type: ignore else: for child in node.children: new_child = find_and_replace_node_content(child, env, need) @@ -151,37 +153,35 @@ def find_and_replace_node_content(node, env: BuildEnvironment, need): return node -def resolve_dynamic_values(env: BuildEnvironment): +def resolve_dynamic_values(needs: Dict[str, NeedsInfoType], app: Sphinx) -> None: """ Resolve dynamic values inside need data. Rough workflow: - #. Parse all needs and their data for a string like [[ my_func(a,b,c) ]] + #. Parse all needs and their field values for a string like ``[[ my_func(a, b, c) ]]`` #. Extract function name and call parameters #. Execute registered function name with extracted call parameters #. Replace original string with return value - :param env: Sphinx environment - :return: return value of given function - """ - data = SphinxNeedsData(env) - workflow = data.get_or_create_workflow() - # Only perform calculation if not already done yet - if workflow["dynamic_values_resolved"]: - return + The registered functions should take the following parameters: - needs = data.get_or_create_needs() + - ``app``: Sphinx application + - ``need``: Need data + - ``all_needs``: All needs of the current sphinx project + - ``*args``: optional arguments (specified in the function string) + - ``**kwargs``: optional keyword arguments (specified in the function string) + """ for need in needs.values(): for need_option in need: if need_option in ["docname", "lineno", "content", "content_node", "content_id"]: # dynamic values in this data are not allowed. continue if not isinstance(need[need_option], (list, set)): - func_call = True + func_call: Optional[str] = "init" while func_call: try: - func_call, func_return = _detect_and_execute(need[need_option], need, env) + func_call, func_return = _detect_and_execute(need[need_option], need, app) except FunctionParsingException: raise SphinxError( "Function definition of {option} in file {file}:{line} has " @@ -205,7 +205,7 @@ def resolve_dynamic_values(env: BuildEnvironment): new_values = [] for element in need[need_option]: try: - func_call, func_return = _detect_and_execute(element, need, env) + func_call, func_return = _detect_and_execute(element, need, app) except FunctionParsingException: raise SphinxError( "Function definition of {option} in file {file}:{line} has " @@ -229,53 +229,44 @@ def resolve_dynamic_values(env: BuildEnvironment): need[need_option] = new_values - # Finally set a flag so that this function gets not executed several times - workflow["dynamic_values_resolved"] = True - -def resolve_variants_options(env: BuildEnvironment): +def resolve_variants_options( + needs: Dict[str, NeedsInfoType], needs_config: NeedsSphinxConfig, tags: Dict[str, bool] +) -> None: """ Resolve variants options inside need data. + These are fields specified by the user, + that have string values with a special markup syntax like ``var_a:open``. + These need to be resolved to the actual value. + Rough workflow: - #. Parse all needs and their data for variant handling + #. Parse all needs and their fields for variant handling #. Replace original string with return value - :param env: Sphinx environment - :return: None """ - data = SphinxNeedsData(env) - workflow = data.get_or_create_workflow() - # Only perform calculation if not already done yet - if workflow["variant_option_resolved"]: - return - - needs_config = NeedsSphinxConfig(env.config) variants_options = needs_config.variant_options - if variants_options: - needs = data.get_or_create_needs() - for need in needs.values(): - # Data to use as filter context. - need_context: Dict[str, Any] = {**need} - need_context.update(**needs_config.filter_data) # Add needs_filter_data to filter context - _sphinx_tags = env.app.builder.tags.tags # Get sphinx tags - need_context.update(**_sphinx_tags) # Add sphinx tags to filter context - - for var_option in variants_options: - if var_option in need and need[var_option] not in (None, "", []): - if not isinstance(need[var_option], (list, set, tuple)): - option_value: str = need[var_option] - need[var_option] = match_variants(option_value, need_context, needs_config.variants) - else: - option_value = need[var_option] - need[var_option] = match_variants(option_value, need_context, needs_config.variants) - - # Finally set a flag so that this function gets not executed several times - workflow["variant_option_resolved"] = True - + if not variants_options: + return -def check_and_get_content(content: str, need, env: BuildEnvironment) -> str: + for need in needs.values(): + # Data to use as filter context. + need_context: Dict[str, Any] = {**need} + need_context.update(**needs_config.filter_data) # Add needs_filter_data to filter context + need_context.update(**tags) # Add sphinx tags to filter context + + for var_option in variants_options: + if var_option in need and need[var_option] not in (None, "", []): + if not isinstance(need[var_option], (list, set, tuple)): + option_value: str = need[var_option] + need[var_option] = match_variants(option_value, need_context, needs_config.variants) + else: + option_value = need[var_option] + need[var_option] = match_variants(option_value, need_context, needs_config.variants) + + +def check_and_get_content(content: str, need: NeedsInfoType, env: BuildEnvironment) -> str: """ Checks if the given content is a function call. If not, content is returned. @@ -290,21 +281,22 @@ def check_and_get_content(content: str, need, env: BuildEnvironment) -> str: try: content = str(content) except UnicodeEncodeError: - content = content.encode("utf-8") + content = content.encode("utf-8") # type: ignore func_match = func_pattern.search(content) if func_match is None: return content func_call = func_match.group(1) # Extract function call - func_return = execute_func(env, need, func_call) # Execute function call and get return value + func_return = execute_func(env.app, need, func_call) # Execute function call and get return value # Replace the function_call with the calculated value content = content.replace(f"[[{func_call}]]", func_return) return content -def _detect_and_execute(content, need, env): +def _detect_and_execute(content: Any, need: NeedsInfoType, app: Sphinx) -> Tuple[Optional[str], Any]: + """Detects if given content is a function call and executes it.""" try: content = str(content) except UnicodeEncodeError: @@ -315,12 +307,12 @@ def _detect_and_execute(content, need, env): return None, None func_call = func_match.group(1) # Extract function call - func_return = execute_func(env, need, func_call) # Execute function call and get return value + func_return = execute_func(app, need, func_call) # Execute function call and get return value return func_call, func_return -def _analyze_func_string(func_string: str, need): +def _analyze_func_string(func_string: str, need: Optional[NeedsInfoType]) -> Tuple[str, List[Any], Dict[str, Any]]: """ Analyze given function string and extract: @@ -336,22 +328,22 @@ def _analyze_func_string(func_string: str, need): try: func = ast.parse(func_string) except SyntaxError as e: - need_id = need["id"] or "UNKNOWN" + need_id = need["id"] if need else "UNKNOWN" raise SphinxError(f"Parsing function string failed for need {need_id}: {func_string}. {e}") try: - func_call = func.body[0].value + func_call = func.body[0].value # type: ignore func_name = func_call.func.id except AttributeError: raise SphinxError(f"Given dynamic function string is not a valid python call. Got: {func_string}") - func_args = [] + func_args: List[Any] = [] for arg in func_call.args: if isinstance(arg, ast.Num): func_args.append(arg.n) elif isinstance(arg, (ast.Str, ast.BoolOp)): - func_args.append(arg.s) + func_args.append(arg.s) # type: ignore elif isinstance(arg, ast.List): - arg_list = [] + arg_list: List[Any] = [] for element in arg.elts: if isinstance(element, ast.Num): arg_list.append(element.n) @@ -359,7 +351,7 @@ def _analyze_func_string(func_string: str, need): arg_list.append(element.s) func_args.append(arg_list) elif isinstance(arg, ast.Attribute): - if arg.value.id == "need" and need: + if arg.value.id == "need" and need: # type: ignore func_args.append(need[arg.attr]) else: raise FunctionParsingException("usage of need attribute not supported.") @@ -375,7 +367,7 @@ def _analyze_func_string(func_string: str, need): "Unsupported type found in function definition: {}. " "Supported are numbers, strings, bool and list".format(func_string) ) - func_kargs = {} + func_kargs: Dict[str, Any] = {} for keyword in func_call.keywords: kvalue = keyword.value kkey = keyword.arg diff --git a/sphinx_needs/layout.py b/sphinx_needs/layout.py index 4bc206285..887d2fea8 100644 --- a/sphinx_needs/layout.py +++ b/sphinx_needs/layout.py @@ -25,7 +25,7 @@ from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.debug import measure_time -from sphinx_needs.utils import INTERNALS, match_string_link, unwrap +from sphinx_needs.utils import INTERNALS, match_string_link @measure_time("need") @@ -44,7 +44,7 @@ def create_need( :param docname: Needed for calculating references :return: """ - env = app.builder.env + env = app.env needs = SphinxNeedsData(env).get_or_create_needs() if need_id not in needs.keys(): @@ -145,7 +145,7 @@ def build_need( The level structure must be kept, otherwise docutils can not handle it! """ - env = app.builder.env + env = app.env needs = SphinxNeedsData(env).get_or_create_needs() node_container = nodes.container() @@ -763,8 +763,8 @@ def image( :return: An inline docutils node element :rtype: :class: docutils.nodes.inline """ - builder = unwrap(self.app.builder) - env = unwrap(builder.env) + builder = self.app.builder + env = self.app.env data_container = nodes.inline() if prefix: @@ -934,7 +934,7 @@ def collapse_button( :param initial: If True, initial status will hide rows after loading page. :return: docutils nodes """ - builder = unwrap(self.app.builder) + builder = self.app.builder if any(x in builder.name.upper() for x in ["PDF", "LATEX"]): # PDF/Latex output do not support collapse functions return None diff --git a/sphinx_needs/need_constraints.py b/sphinx_needs/need_constraints.py index 19f3b618a..77db7d03b 100644 --- a/sphinx_needs/need_constraints.py +++ b/sphinx_needs/need_constraints.py @@ -1,4 +1,6 @@ -from sphinx.application import Sphinx +from typing import Dict + +import jinja2 from sphinx_needs.api.exceptions import NeedsConstraintFailed, NeedsConstraintNotAllowed from sphinx_needs.config import NeedsSphinxConfig @@ -9,102 +11,90 @@ logger = get_logger(__name__) -def process_constraints(app: Sphinx, need: NeedsInfoType) -> None: - """ - Finally creates the need-node in the docurils node-tree. +def process_constraints(needs: Dict[str, NeedsInfoType], config: NeedsSphinxConfig) -> None: + """Analyse constraints of all needs, + and set corresponding fields on the need data item: + ``constraints_passed`` and ``constraints_results``. - :param app: sphinx app for access to config files - :param need: need object to process + The ``style`` field may also be changed, if a constraint fails + (depending on the config value ``constraint_failed_options``) """ - needs_config = NeedsSphinxConfig(app.config) - config_constraints = needs_config.constraints + config_constraints = config.constraints - need_id = need["id"] + error_templates_cache: Dict[str, jinja2.Template] = {} - constraints = need["constraints"] + for need in needs.values(): + need_id = need["id"] + constraints = need["constraints"] - for constraint in constraints: - # check if constraint is defined in config - if constraint not in config_constraints.keys(): - raise NeedsConstraintNotAllowed( - f"Constraint {constraint} of need id {need_id} is not allowed by config value 'needs_constraints'." - ) - else: - # access constraints defined in conf.py - executable_constraints = config_constraints[constraint] + # flag that is set to False if any check fails + need["constraints_passed"] = True - # lazily gather all results to determine results_passed later - results_list = [] + for constraint in constraints: + try: + executable_constraints = config_constraints[constraint] + except KeyError: + # Note, this is already checked for in add_need + raise NeedsConstraintNotAllowed( + f"Constraint {constraint} of need id {need_id} is not allowed by config value 'needs_constraints'." + ) # name is check_0, check_1, ... for name, cmd in executable_constraints.items(): - # compile constraint and check single need if it fulfills constraint - if name != "severity": - # check current need if it meets constraint given in check_0, check_1 in conf.py ... - constraint_passed = filter_single_need(app, need, cmd) - results_list.append(constraint_passed) - - if not constraint_passed: - # prepare structure per name - if constraint not in need["constraints_results"]: - need["constraints_results"][constraint] = {} - - # defines what to do if a constraint is not fulfilled. from conf.py - constraint_failed_options = needs_config.constraint_failed_options - - # prepare structure for check_0, check_1 ... - if name not in need["constraints_results"][constraint]: - need["constraints_results"][constraint][name] = {} - - need["constraints_results"][constraint][name] = False - - # severity of failed constraint - severity = executable_constraints["severity"] - - # configurable force of constraint failed style - force_style = constraint_failed_options[severity]["force_style"] - - actions_on_fail = constraint_failed_options[severity]["on_fail"] - style_on_fail = constraint_failed_options[severity]["style"] - - if "warn" in actions_on_fail: - logger.warning( - f"Constraint {cmd} for need {need_id} FAILED! severity: {severity} [needs]", - type="needs", - color="red", - ) - - if "break" in actions_on_fail: - raise NeedsConstraintFailed( - f"FAILED a breaking constraint: >> {cmd} << for need " - f"{need_id} FAILED! breaking build process" - ) - - old_style = need["style"] - - # append to style if present - if old_style and len(old_style) > 0: - new_styles = "".join(", " + x for x in style_on_fail) - else: - old_style = "" - new_styles = "".join(x + "," for x in style_on_fail) - - if force_style: - need["style"] = new_styles.strip(", ") - else: - constraint_failed_style = old_style + new_styles - need["style"] = constraint_failed_style + if name in ("severity", "error_message"): + # special keys, that are not a check + continue + + # compile constraint and check if need fulfils it + constraint_passed = filter_single_need(need, config, cmd) + + if constraint_passed: + need["constraints_results"].setdefault(constraint, {})[name] = True + else: + need["constraints_results"].setdefault(constraint, {})[name] = False + need["constraints_passed"] = False + + if "error_message" in executable_constraints: + msg = str(executable_constraints["error_message"]) + template = error_templates_cache.setdefault(msg, jinja2.Template(msg)) + need["constraints_error"] = template.render(**need) + + if "severity" not in executable_constraints: + raise NeedsConstraintFailed( + f"'severity' key not set for constraint {constraint!r} in config 'needs_constraints'" + ) + severity = executable_constraints["severity"] + if severity not in config.constraint_failed_options: + raise NeedsConstraintFailed( + f"Severity {severity!r} not set in config 'needs_constraint_failed_options'" + ) + failed_options = config.constraint_failed_options[severity] + + # log/except if needed + if "warn" in failed_options.get("on_fail", []): + logger.warning( + f"Constraint {cmd} for need {need_id} FAILED! severity: {severity} {need.get('constraints_error', '')} [needs.constraint]", + type="needs", + subtype="constraint", + color="red", + location=(need["docname"], need["lineno"]), + ) + if "break" in failed_options.get("on_fail", []): + raise NeedsConstraintFailed( + f"FAILED a breaking constraint: >> {cmd} << for need " + f"{need_id} FAILED! breaking build process" + ) + + # set styles + old_style = need["style"] + if old_style and len(old_style) > 0: + new_styles = "".join(", " + x for x in failed_options.get("style", [])) + else: + old_style = "" + new_styles = "".join(x + "," for x in failed_options.get("style", [])) + if failed_options.get("force_style", False): + need["style"] = new_styles.strip(", ") else: - # constraint is met, fill corresponding need attributes - - # prepare structure - if constraint not in need["constraints_results"].keys(): - need["constraints_results"][constraint] = {} - need["constraints_results"][constraint][name] = constraint_passed - - # access all previous results, if one check failed, set constraints_passed to False for easy filtering - if False in results_list: - need["constraints_passed"] = False - else: - need["constraints_passed"] = True + constraint_failed_style = old_style + new_styles + need["style"] = constraint_failed_style diff --git a/sphinx_needs/needs.py b/sphinx_needs/needs.py index fbe8340d8..13b73d4d7 100644 --- a/sphinx_needs/needs.py +++ b/sphinx_needs/needs.py @@ -11,7 +11,9 @@ import sphinx_needs.debug as debug # Need to set global var in it for timeing measurements from sphinx_needs.builder import ( NeedsBuilder, + NeedsIdBuilder, NeedumlsBuilder, + build_needs_id_json, build_needs_json, build_needumls_pumls, ) @@ -27,14 +29,13 @@ from sphinx_needs.directives.need import ( Need, NeedDirective, - add_sections, + analyse_need_locations, html_depart, html_visit, latex_depart, latex_visit, process_need_nodes, purge_needs, - remove_hidden_needs, ) from sphinx_needs.directives.needbar import Needbar, NeedbarDirective, process_needbar from sphinx_needs.directives.needextend import Needextend, NeedextendDirective @@ -140,6 +141,7 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.add_builder(NeedsBuilder) app.add_builder(NeedumlsBuilder) + app.add_builder(NeedsIdBuilder) NeedsSphinxConfig.add_config_values(app) @@ -211,15 +213,23 @@ def setup(app: Sphinx) -> Dict[str, Any]: # EVENTS ######################################################################## # Make connections to events - app.connect("env-purge-doc", purge_needs) app.connect("config-inited", load_config) + app.connect("config-inited", check_configuration) + app.connect("env-before-read-docs", prepare_env) app.connect("env-before-read-docs", load_external_needs) - app.connect("config-inited", check_configuration) - # app.connect("doctree-resolved", add_sections) - app.connect("doctree-read", add_sections) + + app.connect("env-purge-doc", purge_needs) + + app.connect("doctree-read", analyse_need_locations) + app.connect("env-merge-info", merge_data) + app.connect("env-updated", install_lib_static_files) + app.connect("env-updated", install_permalink_file) + # This should be called last, so that need-styles can override styles from used libraries + app.connect("env-updated", install_styles_static_files) + # There is also the event doctree-read. # But it looks like in this event no references are already solved, which # makes trouble in our code. @@ -230,17 +240,12 @@ def setup(app: Sphinx) -> Dict[str, Any]: app.connect("doctree-resolved", process_creator(NODE_TYPES_PRIO, "needextract"), priority=100) app.connect("doctree-resolved", process_need_nodes) app.connect("doctree-resolved", process_creator(NODE_TYPES)) - app.connect("doctree-resolved", remove_hidden_needs, priority=1000) app.connect("build-finished", process_warnings) app.connect("build-finished", build_needs_json) + app.connect("build-finished", build_needs_id_json) app.connect("build-finished", build_needumls_pumls) app.connect("build-finished", debug.process_timing) - app.connect("env-updated", install_lib_static_files) - app.connect("env-updated", install_permalink_file) - - # This should be called last, so that need-styles can override styles from used libraries - app.connect("env-updated", install_styles_static_files) # Be sure Sphinx-Needs config gets erased before any events or external API calls get executed. # So never but this inside an event. @@ -311,7 +316,7 @@ def load_config(app: Sphinx, *_args: Any) -> None: extra_options = NEEDS_CONFIG.extra_options for option in needs_config.extra_options: if option in extra_options: - log.warning(f'extra_option "{option}" already registered. [needs]', type="needs") + log.warning(f'extra_option "{option}" already registered. [needs.config]', type="needs", subtype="config") NEEDS_CONFIG.extra_options[option] = directives.unchanged # Get extra links and create a dictionary of needed options. @@ -387,7 +392,16 @@ def load_config(app: Sphinx, *_args: Any) -> None: if name not in NEEDS_CONFIG.warnings: NEEDS_CONFIG.warnings[name] = check else: - log.warning(f'{name} for "warnings" is already registered. [needs]', type="needs") + log.warning( + f"{name!r} in 'needs_warnings' is already registered. [needs.config]", type="needs", subtype="config" + ) + + if needs_config.constraints_failed_color: + log.warning( + 'Config option "needs_constraints_failed_color" is deprecated. Please use "needs_constraint_failed_options" styles instead. [needs.config]', + type="needs", + subtype="config", + ) def visitor_dummy(*_args: Any, **_kwargs: Any) -> None: @@ -475,8 +489,6 @@ def prepare_env(app: Sphinx, env: BuildEnvironment, _docname: str) -> None: needs_config.flow_configs.update(NEEDFLOW_CONFIG_DEFAULTS) - data.get_or_create_workflow() - # Set time measurement flag if needs_config.debug_measurement: debug.START_TIME = timer() # Store the rough start time of Sphinx build diff --git a/sphinx_needs/needsfile.py b/sphinx_needs/needsfile.py index 625a4a657..23a06d6fc 100644 --- a/sphinx_needs/needsfile.py +++ b/sphinx_needs/needsfile.py @@ -93,13 +93,17 @@ def wipe_version(self, version: str) -> None: if version in self.needs_list["versions"]: del self.needs_list["versions"][version] - def write_json(self, needs_file: str = "needs.json") -> None: + def write_json(self, needs_file: str = "needs.json", needs_path: str = "") -> None: # We need to rewrite some data, because this kind of data gets overwritten during needs.json import. self.needs_list["created"] = datetime.now().isoformat() self.needs_list["current_version"] = self.current_version self.needs_list["project"] = self.project + if needs_path: + needs_dir = needs_path + else: + needs_dir = self.outdir - with open(os.path.join(self.outdir, needs_file), "w") as f: + with open(os.path.join(needs_dir, needs_file), "w") as f: json.dump(self.needs_list, f, indent=4, sort_keys=True) def load_json(self, file: str) -> None: diff --git a/sphinx_needs/roles/need_count.py b/sphinx_needs/roles/need_count.py index f4aa8dd41..cfe996c7b 100644 --- a/sphinx_needs/roles/need_count.py +++ b/sphinx_needs/roles/need_count.py @@ -10,10 +10,10 @@ from sphinx.application import Sphinx from sphinx_needs.api.exceptions import NeedsInvalidFilter +from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import SphinxNeedsData from sphinx_needs.filter_common import filter_needs, prepare_need_list from sphinx_needs.logging import get_logger -from sphinx_needs.utils import unwrap log = get_logger(__name__) @@ -25,22 +25,20 @@ class NeedCount(nodes.Inline, nodes.Element): # type: ignore def process_need_count( app: Sphinx, doctree: nodes.document, _fromdocname: str, found_nodes: List[nodes.Element] ) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) - # for node_need_count in doctree.findall(NeedCount): + needs_config = NeedsSphinxConfig(app.config) for node_need_count in found_nodes: - all_needs = list(SphinxNeedsData(env).get_or_create_needs().values()) + all_needs = list(SphinxNeedsData(app.env).get_or_create_needs().values()) filter = node_need_count["reftarget"] if filter: filters = filter.split(" ? ") if len(filters) == 1: need_list = prepare_need_list(all_needs) # adds parts to need_list - amount = str(len(filter_needs(app, need_list, filters[0]))) + amount = str(len(filter_needs(need_list, needs_config, filters[0]))) elif len(filters) == 2: need_list = prepare_need_list(all_needs) # adds parts to need_list - amount_1 = len(filter_needs(app, need_list, filters[0])) - amount_2 = len(filter_needs(app, need_list, filters[1])) + amount_1 = len(filter_needs(need_list, needs_config, filters[0])) + amount_2 = len(filter_needs(need_list, needs_config, filters[1])) amount = f"{amount_1 / amount_2 * 100:2.1f}" elif len(filters) > 2: raise NeedsInvalidFilter( diff --git a/sphinx_needs/roles/need_func.py b/sphinx_needs/roles/need_func.py index 8cc346897..32ae6a7c6 100644 --- a/sphinx_needs/roles/need_func.py +++ b/sphinx_needs/roles/need_func.py @@ -9,7 +9,6 @@ from sphinx_needs.functions.functions import check_and_get_content from sphinx_needs.logging import get_logger -from sphinx_needs.utils import unwrap log = get_logger(__name__) @@ -21,10 +20,9 @@ class NeedFunc(nodes.Inline, nodes.Element): # type: ignore def process_need_func( app: Sphinx, doctree: nodes.document, _fromdocname: str, found_nodes: List[nodes.Element] ) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) + env = app.env # for node_need_func in doctree.findall(NeedFunc): for node_need_func in found_nodes: - result = check_and_get_content(node_need_func.attributes["reftarget"], {"id": "need_func_dummy"}, env) + result = check_and_get_content(node_need_func.attributes["reftarget"], {"id": "need_func_dummy"}, env) # type: ignore new_node_func = nodes.Text(str(result)) node_need_func.replace_self(new_node_func) diff --git a/sphinx_needs/roles/need_incoming.py b/sphinx_needs/roles/need_incoming.py index e32900d10..bbeb9b141 100644 --- a/sphinx_needs/roles/need_incoming.py +++ b/sphinx_needs/roles/need_incoming.py @@ -7,7 +7,7 @@ from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import SphinxNeedsData from sphinx_needs.errors import NoUri -from sphinx_needs.utils import check_and_calc_base_url_rel_path, logger, unwrap +from sphinx_needs.utils import check_and_calc_base_url_rel_path, logger class NeedIncoming(nodes.Inline, nodes.Element): # type: ignore @@ -17,8 +17,8 @@ class NeedIncoming(nodes.Inline, nodes.Element): # type: ignore def process_need_incoming( app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element] ) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env needs_config = NeedsSphinxConfig(env.config) all_needs = SphinxNeedsData(env).get_or_create_needs() diff --git a/sphinx_needs/roles/need_outgoing.py b/sphinx_needs/roles/need_outgoing.py index 38a05b8cd..3a7ba1c9e 100644 --- a/sphinx_needs/roles/need_outgoing.py +++ b/sphinx_needs/roles/need_outgoing.py @@ -8,7 +8,7 @@ from sphinx_needs.data import SphinxNeedsData from sphinx_needs.errors import NoUri from sphinx_needs.logging import get_logger -from sphinx_needs.utils import check_and_calc_base_url_rel_path, unwrap +from sphinx_needs.utils import check_and_calc_base_url_rel_path log = get_logger(__name__) @@ -20,8 +20,8 @@ class NeedOutgoing(nodes.Inline, nodes.Element): # type: ignore def process_need_outgoing( app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element] ) -> None: - builder = unwrap(app.builder) - env = unwrap(app.env) + builder = app.builder + env = app.env needs_config = NeedsSphinxConfig(app.config) report_dead_links = needs_config.report_dead_links # for node_need_ref in doctree.findall(NeedOutgoing): diff --git a/sphinx_needs/roles/need_part.py b/sphinx_needs/roles/need_part.py index 0246069ce..e6be611c5 100644 --- a/sphinx_needs/roles/need_part.py +++ b/sphinx_needs/roles/need_part.py @@ -16,7 +16,6 @@ from sphinx_needs.data import NeedsInfoType from sphinx_needs.logging import get_logger -from sphinx_needs.utils import unwrap log = get_logger(__name__) @@ -33,8 +32,8 @@ def process_need_part(app: Sphinx, doctree: nodes.document, fromdocname: str, fo def update_need_with_parts(env: BuildEnvironment, need: NeedsInfoType, part_nodes: List[NeedPart]) -> None: - app = unwrap(env.app) - builder = unwrap(app.builder) + app = env.app + builder = app.builder for part_node in part_nodes: content = cast(str, part_node.children[0].children[0]) # ->inline->Text result = part_pattern.match(content) diff --git a/sphinx_needs/roles/need_ref.py b/sphinx_needs/roles/need_ref.py index d7f839ec5..d054766e6 100644 --- a/sphinx_needs/roles/need_ref.py +++ b/sphinx_needs/roles/need_ref.py @@ -10,7 +10,7 @@ from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.errors import NoUri from sphinx_needs.logging import get_logger -from sphinx_needs.utils import check_and_calc_base_url_rel_path, unwrap +from sphinx_needs.utils import check_and_calc_base_url_rel_path log = get_logger(__name__) @@ -51,8 +51,8 @@ def transform_need_to_dict(need: NeedsInfoType) -> Dict[str, str]: def process_need_ref(app: Sphinx, doctree: nodes.document, fromdocname: str, found_nodes: List[nodes.Element]) -> None: - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env needs_config = NeedsSphinxConfig(env.config) all_needs = SphinxNeedsData(env).get_or_create_needs() # for node_need_ref in doctree.findall(NeedRef): diff --git a/sphinx_needs/utils.py b/sphinx_needs/utils.py index 2ad3db321..5790c552e 100644 --- a/sphinx_needs/utils.py +++ b/sphinx_needs/utils.py @@ -130,8 +130,8 @@ def row_col_maker( :param prefix: string, which is used as prefix for the text output :return: column object (nodes.entry) """ - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env needs_config = NeedsSphinxConfig(env.config) row_col = nodes.entry(classes=["needs_" + need_key]) @@ -238,7 +238,7 @@ def rstjinja(app: Sphinx, docname: str, source: List[str]) -> None: """ Render our pages as a jinja template for fancy templating goodness. """ - builder = unwrap(app.builder) + builder = app.builder # Make sure we're outputting HTML if builder.format != "html": return @@ -383,8 +383,8 @@ def jinja_parse(context: Dict[str, Any], jinja_string: str) -> str: def save_matplotlib_figure(app: Sphinx, figure: FigureBase, basename: str, fromdocname: str) -> nodes.image: - builder = unwrap(app.builder) - env = unwrap(builder.env) + builder = app.builder + env = app.env image_folder = os.path.join(builder.outdir, builder.imagedir) os.makedirs(image_folder, exist_ok=True) @@ -573,14 +573,6 @@ def clean_log(data: str) -> str: return clean_credentials -T = TypeVar("T") - - -def unwrap(obj: Optional[T]) -> T: - assert obj is not None - return obj - - def node_match(node_types: Union[Type[nodes.Element], List[Type[nodes.Element]]]) -> Callable[[nodes.Node], bool]: """ Returns a condition function for doctuils.nodes.findall() diff --git a/sphinx_needs/warnings.py b/sphinx_needs/warnings.py index 950f138a0..8754551dc 100644 --- a/sphinx_needs/warnings.py +++ b/sphinx_needs/warnings.py @@ -11,7 +11,6 @@ from sphinx_needs.data import NeedsInfoType, SphinxNeedsData from sphinx_needs.filter_common import filter_needs from sphinx_needs.logging import get_logger -from sphinx_needs.utils import unwrap logger = get_logger(__name__) @@ -32,9 +31,10 @@ def process_warnings(app: Sphinx, exception: Optional[Exception]) -> None: if exception: return - env = unwrap(app.env) + env = app.env + needs = SphinxNeedsData(env).get_or_create_needs() # If no needs were defined, we do not need to do anything - if not hasattr(env, "needs_all_needs"): + if not needs: return # Check if warnings already got executed. @@ -45,15 +45,14 @@ def process_warnings(app: Sphinx, exception: Optional[Exception]) -> None: env.needs_warnings_executed = True # type: ignore[attr-defined] - needs = SphinxNeedsData(env).get_or_create_needs() - # Exclude external needs for warnings check checked_needs: Dict[str, NeedsInfoType] = {} for need_id, need in needs.items(): if not need["is_external"]: checked_needs[need_id] = need - warnings_always_warn = NeedsSphinxConfig(app.config).warnings_always_warn + needs_config = NeedsSphinxConfig(app.config) + warnings_always_warn = needs_config.warnings_always_warn with logging.pending_logging(): logger.info("\nChecking sphinx-needs warnings") @@ -61,7 +60,7 @@ def process_warnings(app: Sphinx, exception: Optional[Exception]) -> None: for warning_name, warning_filter in NEEDS_CONFIG.warnings.items(): if isinstance(warning_filter, str): # filter string used - result = filter_needs(app, checked_needs.values(), warning_filter) + result = filter_needs(checked_needs.values(), needs_config, warning_filter) elif callable(warning_filter): # custom defined filter code used from conf.py result = [] diff --git a/tests/__snapshots__/test_api_configuration.ambr b/tests/__snapshots__/test_api_configuration.ambr new file mode 100644 index 000000000..9ce0b2fa0 --- /dev/null +++ b/tests/__snapshots__/test_api_configuration.ambr @@ -0,0 +1,40 @@ +# serializer version: 1 +# name: test_api_add_type[test_app0] + list([ + dict({ + 'color': '#BFD8D2', + 'directive': 'story', + 'prefix': 'US_', + 'style': 'node', + 'title': 'User Story', + }), + dict({ + 'color': '#FEDCD2', + 'directive': 'spec', + 'prefix': 'SP_', + 'style': 'node', + 'title': 'Specification', + }), + dict({ + 'color': '#DF744A', + 'directive': 'impl', + 'prefix': 'IM_', + 'style': 'node', + 'title': 'Implementation', + }), + dict({ + 'color': '#DCB239', + 'directive': 'test', + 'prefix': 'TC_', + 'style': 'node', + 'title': 'Test Case', + }), + dict({ + 'color': '#000000', + 'directive': 'awesome', + 'prefix': 'AW_', + 'style': 'cloud', + 'title': 'Awesome', + }), + ]) +# --- diff --git a/tests/__snapshots__/test_basic_doc.ambr b/tests/__snapshots__/test_basic_doc.ambr new file mode 100644 index 000000000..7f0ae5eb5 --- /dev/null +++ b/tests/__snapshots__/test_basic_doc.ambr @@ -0,0 +1,161 @@ +# serializer version: 1 +# name: test_build_needs[test_app0] + dict({ + 'current_version': '', + 'project': 'Python', + 'versions': dict({ + '': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'ST_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'ST_001', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test story', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'ST_001', + 'id_complete': 'ST_001', + 'id_parent': 'ST_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Welcome to basic test’s documentation!', + 'sections': list([ + 'Welcome to basic test’s documentation!', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + ]), + 'target_id': 'ST_001', + 'template': None, + 'title': 'Test story', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'US_38823': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'US_38823', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'No ID', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'US_38823', + 'id_complete': 'US_38823', + 'id_parent': 'US_38823', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Welcome to basic test’s documentation!', + 'sections': list([ + 'Welcome to basic test’s documentation!', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + ]), + 'target_id': 'US_38823', + 'template': None, + 'title': 'No ID', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 2, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_basic_doc/test_build_html_parallel[test_app0].doctree.xml b/tests/__snapshots__/test_basic_doc/test_build_html_parallel[test_app0].doctree.xml new file mode 100644 index 000000000..1ea1a6d60 --- /dev/null +++ b/tests/__snapshots__/test_basic_doc/test_build_html_parallel[test_app0].doctree.xml @@ -0,0 +1,12 @@ + +
+ + TEST DOCUMENT + <target anonymous="" ids="SP_TOO_001" refid="SP_TOO_001"> + <Need classes="need need-spec" ids="SP_TOO_001" refid="SP_TOO_001"> + <paragraph> + The Tool awesome shall have a command line interface. + <target anonymous="" ids="US_63252" refid="US_63252"> + <Need classes="need need-story" ids="US_63252" refid="US_63252"> + <target refid="needfilter-index-0"> + <Needfilter ids="needfilter-index-0"> diff --git a/tests/__snapshots__/test_export_id.ambr b/tests/__snapshots__/test_export_id.ambr new file mode 100644 index 000000000..6f26b2cb8 --- /dev/null +++ b/tests/__snapshots__/test_export_id.ambr @@ -0,0 +1,821 @@ +# serializer version: 1 +# name: test_export_id[test_app0] + dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + 'FLOW_1': dict({ + 'amount': 10, + 'export_id': 'FLOW_1', + 'filter': '', + 'result': list([ + 'REQ_001', + 'REQ_002', + 'REQ_003', + 'REQ_004', + 'REQ_005', + 'TEST_001', + 'TEST_002', + 'TEST_003', + 'REQ_005.1', + 'REQ_005.cool', + ]), + 'status': list([ + ]), + 'tags': list([ + ]), + 'types': list([ + ]), + }), + 'FLOW_2': dict({ + 'amount': 5, + 'export_id': 'FLOW_2', + 'filter': 'is_need is False or type != "story"', + 'result': list([ + 'TEST_001', + 'TEST_002', + 'TEST_003', + 'REQ_005.1', + 'REQ_005.cool', + ]), + 'status': list([ + ]), + 'tags': list([ + ]), + 'types': list([ + ]), + }), + 'LIST_1': dict({ + 'amount': 10, + 'export_id': 'LIST_1', + 'filter': '', + 'result': list([ + 'REQ_001', + 'REQ_002', + 'REQ_003', + 'REQ_004', + 'REQ_005', + 'TEST_001', + 'TEST_002', + 'TEST_003', + 'REQ_005.1', + 'REQ_005.cool', + ]), + 'status': list([ + ]), + 'tags': list([ + ]), + 'types': list([ + ]), + }), + 'TABLE_1': dict({ + 'amount': 10, + 'export_id': 'TABLE_1', + 'filter': '', + 'result': list([ + 'REQ_001', + 'REQ_002', + 'REQ_003', + 'REQ_004', + 'REQ_005', + 'TEST_001', + 'TEST_002', + 'TEST_003', + 'REQ_005.1', + 'REQ_005.cool', + ]), + 'status': list([ + ]), + 'tags': list([ + ]), + 'types': list([ + ]), + }), + 'TABLE_2': dict({ + 'amount': 3, + 'export_id': 'TABLE_2', + 'filter': '"test" in type', + 'result': list([ + 'TEST_001', + 'TEST_002', + 'TEST_003', + ]), + 'status': list([ + ]), + 'tags': list([ + ]), + 'types': list([ + ]), + }), + }), + 'filters_amount': 5, + 'needs': dict({ + 'REQ_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + 'REQ_003', + ]), + 'blocks_back': list([ + 'REQ_005', + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_001', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_001', + 'id_complete': 'REQ_001', + 'id_parent': 'REQ_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'REQ_002', + 'REQ_004', + 'REQ_003', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Stories', + 'sections': list([ + 'Stories', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_001', + 'template': None, + 'tests': list([ + ]), + 'tests_back': list([ + 'TEST_001', + 'TEST_002', + ]), + 'title': 'My requirement', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_002': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_002', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My requirement 2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_002', + 'id_complete': 'REQ_002', + 'id_parent': 'REQ_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Stories', + 'sections': list([ + 'Stories', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_002', + 'template': None, + 'tests': list([ + ]), + 'tests_back': list([ + ]), + 'title': 'My requirement 2', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_003': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + 'REQ_001', + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_003', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My requirement 3', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_003', + 'id_complete': 'REQ_003', + 'id_parent': 'REQ_003', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Stories', + 'sections': list([ + 'Stories', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_003', + 'template': None, + 'tests': list([ + ]), + 'tests_back': list([ + 'TEST_001', + ]), + 'title': 'My requirement 3', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_004': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_004', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My requirement 4', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_004', + 'id_complete': 'REQ_004', + 'id_parent': 'REQ_004', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Stories', + 'sections': list([ + 'Stories', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_004', + 'template': None, + 'tests': list([ + ]), + 'tests_back': list([ + ]), + 'title': 'My requirement 4', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_005': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + 'REQ_001', + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_005', + 'created_at': '', + 'delete': None, + 'description': ''' + :need_part:`(1) awesome part` + + :need_part:`(cool) a cool part` + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Req 5', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_005', + 'id_complete': 'REQ_005', + 'id_parent': 'REQ_005', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'REQ_001', + 'REQ_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + '1': dict({ + 'content': ' awesome part', + 'document': 'index', + 'id': '1', + 'is_need': False, + 'is_part': True, + 'links': list([ + ]), + 'links_back': list([ + 'TEST_003', + ]), + 'tests_back': list([ + 'TEST_003', + ]), + }), + 'cool': dict({ + 'content': ' a cool part', + 'document': 'index', + 'id': 'cool', + 'is_need': False, + 'is_part': True, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'tests_back': list([ + 'TEST_003', + ]), + }), + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Stories', + 'sections': list([ + 'Stories', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_005', + 'template': None, + 'tests': list([ + ]), + 'tests_back': list([ + 'TEST_003', + ]), + 'title': 'Req 5', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TEST_001', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test of requirements', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_001', + 'id_complete': 'TEST_001', + 'id_parent': 'TEST_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Tests', + 'sections': list([ + 'Tests', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TEST_001', + 'template': None, + 'tests': list([ + 'REQ_001', + 'REQ_003', + ]), + 'tests_back': list([ + ]), + 'title': 'Test of requirements', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_002': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TEST_002', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test of requirements2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_002', + 'id_complete': 'TEST_002', + 'id_parent': 'TEST_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'TEST_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Tests', + 'sections': list([ + 'Tests', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TEST_002', + 'template': None, + 'tests': list([ + 'REQ_001', + ]), + 'tests_back': list([ + ]), + 'title': 'Test of requirements2', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_003': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'blocks': list([ + ]), + 'blocks_back': list([ + ]), + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TEST_003', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test of requirements 5', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_003', + 'id_complete': 'TEST_003', + 'id_parent': 'TEST_003', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'REQ_005.1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Tests', + 'sections': list([ + 'Tests', + 'EXTRA LINKS DOCUMENT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TEST_003', + 'template': None, + 'tests': list([ + 'REQ_005.1', + 'REQ_005.cool', + ]), + 'tests_back': list([ + ]), + 'title': 'Test of requirements 5', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 8, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_external.ambr b/tests/__snapshots__/test_external.ambr new file mode 100644 index 000000000..04d9a5e6c --- /dev/null +++ b/tests/__snapshots__/test_external.ambr @@ -0,0 +1,382 @@ +# serializer version: 1 +# name: test_external_json[test_app0] + dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'EXT_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': 'EXT_TEST_01', + 'docname': None, + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': 'http://my_company.com/docs/v1/index.html#TEST_01', + 'full_title': 'TEST_01 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'EXT_TEST_01', + 'id_complete': 'EXT_TEST_01', + 'id_parent': 'EXT_TEST_01', + 'id_prefix': '', + 'is_external': True, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'SPEC_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': '', + 'sections': list([ + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'EXT_TEST_01', + 'template': None, + 'title': 'TEST_01 DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'EXT_TEST_02': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': 'EXT_TEST_02', + 'docname': None, + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': 'http://my_company.com/docs/v1/index.html#TEST_02', + 'full_title': 'TEST_02 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'EXT_TEST_02', + 'id_complete': 'EXT_TEST_02', + 'id_parent': 'EXT_TEST_02', + 'id_prefix': '', + 'is_external': True, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'EXT_TEST_01', + 'REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': '', + 'sections': list([ + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'test_02', + 'test', + ]), + 'target_id': 'EXT_TEST_02', + 'template': None, + 'title': 'TEST_02 DESCRIPTION', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test requirement 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_1', + 'id_complete': 'REQ_1', + 'id_parent': 'REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT EXTERNAL', + 'sections': list([ + 'TEST DOCUMENT EXTERNAL', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_1', + 'template': None, + 'title': 'Test requirement 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SPEC_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'SPEC_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test specification 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SPEC_1', + 'id_complete': 'SPEC_1', + 'id_parent': 'SPEC_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'REQ_1', + 'EXT_TEST_01', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT EXTERNAL', + 'sections': list([ + 'TEST DOCUMENT EXTERNAL', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SPEC_1', + 'template': None, + 'title': 'Test specification 1', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SUB_002': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'SUB_002', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'subfolder_a/subfolder_b/subpage', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Sub-Req', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SUB_002', + 'id_complete': 'SUB_002', + 'id_parent': 'SUB_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Subpage', + 'sections': list([ + 'Subpage', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SUB_002', + 'template': None, + 'title': 'Sub-Req', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 5, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_import.ambr b/tests/__snapshots__/test_import.ambr new file mode 100644 index 000000000..017f2081d --- /dev/null +++ b/tests/__snapshots__/test_import.ambr @@ -0,0 +1,4994 @@ +# serializer version: 1 +# name: test_import_builder[test_app0] + dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'IMPL_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'IMPL_01', + 'created_at': '', + 'delete': False, + 'description': 'Incoming links of this spec: :need_incoming:`IMPL_01`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Implementation for specification', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'IMPL_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'OWN_ID_123', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'IMPL_01', + 'template': None, + 'title': 'Implementation for specification', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'OWN_ID_123': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'OWN_ID_123', + 'created_at': '', + 'delete': False, + 'description': 'Outgoing links of this spec: :need_outgoing:`OWN_ID_123`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification of a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'OWN_ID_123', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'R_F4722', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'OWN_ID_123', + 'template': None, + 'title': 'Specification of a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_001', + 'created_at': '', + 'delete': False, + 'description': ''' + This is an awesome requirement and it includes a nice title, + a given id, a tag and this text as description. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'example', + ]), + 'target_id': 'REQ_001', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test requirement 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_1', + 'template': None, + 'title': 'Test requirement 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'ROLES_REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'ROLES_REQ_1', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Sliced Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'ROLES_REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'ROLES_REQ_1', + 'template': None, + 'title': 'Sliced Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'ROLES_REQ_2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'ROLES_REQ_2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Butter on Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'ROLES_REQ_2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'ROLES_REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'ROLES_REQ_2', + 'template': None, + 'title': 'Butter on Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'R_22EB2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'R_22EB2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'R_22EB2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'B', + 'filter', + ]), + 'target_id': 'R_22EB2', + 'template': None, + 'title': 'Requirement B', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'R_2A9D0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'R_2A9D0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'R_2A9D0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'A', + 'filter', + ]), + 'target_id': 'R_2A9D0', + 'template': None, + 'title': 'Requirement A', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'R_F4722': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'R_F4722', + 'created_at': '', + 'delete': False, + 'description': ''' + This is my **first** requirement!! + + .. note:: You can use any rst code inside it :) + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'R_F4722', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'requirement', + 'test', + 'awesome', + ]), + 'target_id': 'R_F4722', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SPEC_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'SPEC_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test specification 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SPEC_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SPEC_1', + 'template': None, + 'title': 'Test specification 1', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'S_01A67': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'S_01A67', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'S_01A67', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'B', + 'filter', + ]), + 'target_id': 'S_01A67', + 'template': None, + 'title': 'Specification B', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'S_503A1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'S_503A1', + 'created_at': '', + 'delete': False, + 'description': ''' + We haven't set an **ID** here, so sphinxcontrib-needs + will generated one for us. + + But we have **set a link** to our first requirement and + also a *status* is given. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Spec for a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'S_503A1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'REQ_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'done', + 'style': None, + 'tags': list([ + 'important', + 'example', + ]), + 'target_id': 'S_503A1', + 'template': None, + 'title': 'Spec for a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'S_D70B0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'S_D70B0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'S_D70B0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'A', + 'filter', + ]), + 'target_id': 'S_D70B0', + 'template': None, + 'title': 'Specification A', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TEST_01', + 'created_at': '', + 'delete': False, + 'description': 'TEST IMPORT TITLE', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST IMPORT DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TEST_01', + 'template': None, + 'title': 'TEST IMPORT DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'T_5CCAA': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'T_5CCAA', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'T_5CCAA', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + 'T_C3893', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'awesome', + 'filter', + ]), + 'target_id': 'T_5CCAA', + 'template': None, + 'title': 'Test 1', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'T_C3893': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This test checks :need:`impl_01` for :need:`OWN_ID_123` inside a + Python 2.7 environment. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test for XY', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'T_C3893', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'OWN_ID_123', + 'IMPL_01', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'T_5CCAA', + 'parent_needs': list([ + 'T_5CCAA', + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT IMPORT', + 'sections': list([ + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'implemented', + 'style': None, + 'tags': list([ + 'test', + 'user_interface', + 'python27', + ]), + 'target_id': 'T_C3893', + 'template': None, + 'title': 'Test for XY', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_IMPL_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_IMPL_01', + 'created_at': '', + 'delete': False, + 'description': 'Incoming links of this spec: :need_incoming:`collapsed_IMPL_01`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Implementation for specification', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_IMPL_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'collapsed_OWN_ID_123', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_IMPL_01', + 'template': None, + 'title': 'Implementation for specification', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_OWN_ID_123': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_OWN_ID_123', + 'created_at': '', + 'delete': False, + 'description': 'Outgoing links of this spec: :need_outgoing:`collapsed_OWN_ID_123`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification of a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_OWN_ID_123', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'collapsed_R_F4722', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_OWN_ID_123', + 'template': None, + 'title': 'Specification of a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_REQ_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_REQ_001', + 'created_at': '', + 'delete': False, + 'description': ''' + This is an awesome requirement and it includes a nice title, + a given id, a tag and this text as description. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_REQ_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'example', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_REQ_001', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_ROLES_REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_ROLES_REQ_1', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Sliced Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_ROLES_REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_ROLES_REQ_1', + 'template': None, + 'title': 'Sliced Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_ROLES_REQ_2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_ROLES_REQ_2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Butter on Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_ROLES_REQ_2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'collapsed_ROLES_REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_ROLES_REQ_2', + 'template': None, + 'title': 'Butter on Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_R_22EB2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_R_22EB2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_R_22EB2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_R_22EB2', + 'template': None, + 'title': 'Requirement B', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_R_2A9D0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_R_2A9D0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_R_2A9D0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_R_2A9D0', + 'template': None, + 'title': 'Requirement A', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_R_F4722': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_R_F4722', + 'created_at': '', + 'delete': False, + 'description': ''' + This is my **first** requirement!! + + .. note:: You can use any rst code inside it :) + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_R_F4722', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'requirement', + 'test', + 'awesome', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_R_F4722', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_S_01A67': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_S_01A67', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_S_01A67', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_S_01A67', + 'template': None, + 'title': 'Specification B', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_S_503A1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_S_503A1', + 'created_at': '', + 'delete': False, + 'description': ''' + We haven't set an **ID** here, so sphinxcontrib-needs + will generated one for us. + + But we have **set a link** to our first requirement and + also a *status* is given. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Spec for a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_S_503A1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'collapsed_REQ_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'done', + 'style': None, + 'tags': list([ + 'important', + 'example', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_S_503A1', + 'template': None, + 'title': 'Spec for a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_S_D70B0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_S_D70B0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_S_D70B0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_S_D70B0', + 'template': None, + 'title': 'Specification A', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_TEST_01', + 'created_at': '', + 'delete': False, + 'description': 'TEST IMPORT TITLE', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST IMPORT DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_TEST_01', + 'template': None, + 'title': 'TEST IMPORT DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_T_5CCAA': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'collapsed_T_5CCAA', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_T_5CCAA', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + 'collapsed_T_C3893', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'awesome', + 'filter', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_T_5CCAA', + 'template': None, + 'title': 'Test 1', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'collapsed_T_C3893': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This test checks :need:`impl_01` for :need:`collapsed_OWN_ID_123` inside a + Python 2.7 environment. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test for XY', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'collapsed_T_C3893', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'collapsed_OWN_ID_123', + 'collapsed_IMPL_01', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'collapsed_T_5CCAA', + 'parent_needs': list([ + 'collapsed_T_5CCAA', + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'COLLAPSED', + 'sections': list([ + 'COLLAPSED', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'implemented', + 'style': None, + 'tags': list([ + 'test', + 'user_interface', + 'python27', + 'should', + 'be', + 'collapsed', + ]), + 'target_id': 'collapsed_T_C3893', + 'template': None, + 'title': 'Test for XY', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_IMPL_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': 'Incoming links of this spec: :need_incoming:`hidden_IMPL_01`.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Implementation for specification', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_IMPL_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'hidden_OWN_ID_123', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_TEST_01', + 'parent_needs': list([ + 'hidden_TEST_01', + ]), + 'parent_needs_back': list([ + 'hidden_OWN_ID_123', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'hidden', + ]), + 'target_id': 'hidden_IMPL_01', + 'template': None, + 'title': 'Implementation for specification', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_OWN_ID_123': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': 'Outgoing links of this spec: :need_outgoing:`hidden_OWN_ID_123`.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification of a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_OWN_ID_123', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'hidden_R_F4722', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_IMPL_01', + 'parent_needs': list([ + 'hidden_IMPL_01', + ]), + 'parent_needs_back': list([ + 'hidden_REQ_001', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'hidden', + ]), + 'target_id': 'hidden_OWN_ID_123', + 'template': None, + 'title': 'Specification of a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_REQ_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This is an awesome requirement and it includes a nice title, + a given id, a tag and this text as description. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_REQ_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_OWN_ID_123', + 'parent_needs': list([ + 'hidden_OWN_ID_123', + ]), + 'parent_needs_back': list([ + 'hidden_ROLES_REQ_1', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'example', + 'hidden', + ]), + 'target_id': 'hidden_REQ_001', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_ROLES_REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Sliced Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_ROLES_REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_REQ_001', + 'parent_needs': list([ + 'hidden_REQ_001', + ]), + 'parent_needs_back': list([ + 'hidden_ROLES_REQ_2', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'hidden', + ]), + 'target_id': 'hidden_ROLES_REQ_1', + 'template': None, + 'title': 'Sliced Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_ROLES_REQ_2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Butter on Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_ROLES_REQ_2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'hidden_ROLES_REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_ROLES_REQ_1', + 'parent_needs': list([ + 'hidden_ROLES_REQ_1', + ]), + 'parent_needs_back': list([ + 'hidden_R_22EB2', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'hidden', + ]), + 'target_id': 'hidden_ROLES_REQ_2', + 'template': None, + 'title': 'Butter on Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_R_22EB2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_R_22EB2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_ROLES_REQ_2', + 'parent_needs': list([ + 'hidden_ROLES_REQ_2', + ]), + 'parent_needs_back': list([ + 'hidden_R_2A9D0', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'hidden', + ]), + 'target_id': 'hidden_R_22EB2', + 'template': None, + 'title': 'Requirement B', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_R_2A9D0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_R_2A9D0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_R_22EB2', + 'parent_needs': list([ + 'hidden_R_22EB2', + ]), + 'parent_needs_back': list([ + 'hidden_R_F4722', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'hidden', + ]), + 'target_id': 'hidden_R_2A9D0', + 'template': None, + 'title': 'Requirement A', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_R_F4722': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This is my **first** requirement!! + + .. note:: You can use any rst code inside it :) + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_R_F4722', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_R_2A9D0', + 'parent_needs': list([ + 'hidden_R_2A9D0', + ]), + 'parent_needs_back': list([ + 'hidden_S_01A67', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'requirement', + 'test', + 'awesome', + 'hidden', + ]), + 'target_id': 'hidden_R_F4722', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_S_01A67': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_S_01A67', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_R_F4722', + 'parent_needs': list([ + 'hidden_R_F4722', + ]), + 'parent_needs_back': list([ + 'hidden_S_503A1', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'hidden', + ]), + 'target_id': 'hidden_S_01A67', + 'template': None, + 'title': 'Specification B', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_S_503A1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + We haven't set an **ID** here, so sphinxcontrib-needs + will generated one for us. + + But we have **set a link** to our first requirement and + also a *status* is given. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Spec for a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_S_503A1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'hidden_REQ_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_S_01A67', + 'parent_needs': list([ + 'hidden_S_01A67', + ]), + 'parent_needs_back': list([ + 'hidden_S_D70B0', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'done', + 'style': None, + 'tags': list([ + 'important', + 'example', + 'hidden', + ]), + 'target_id': 'hidden_S_503A1', + 'template': None, + 'title': 'Spec for a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_S_D70B0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_S_D70B0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_S_503A1', + 'parent_needs': list([ + 'hidden_S_503A1', + ]), + 'parent_needs_back': list([ + 'hidden_T_5CCAA', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'hidden', + ]), + 'target_id': 'hidden_S_D70B0', + 'template': None, + 'title': 'Specification A', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': 'TEST IMPORT TITLE', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST IMPORT DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + 'hidden_IMPL_01', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'hidden', + ]), + 'target_id': 'hidden_TEST_01', + 'template': None, + 'title': 'TEST IMPORT DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_T_5CCAA': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_T_5CCAA', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_S_D70B0', + 'parent_needs': list([ + 'hidden_S_D70B0', + ]), + 'parent_needs_back': list([ + 'hidden_T_C3893', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'awesome', + 'filter', + 'hidden', + ]), + 'target_id': 'hidden_T_5CCAA', + 'template': None, + 'title': 'Test 1', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'hidden_T_C3893': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This test checks :need:`impl_01` for :need:`hidden_OWN_ID_123` inside a + Python 2.7 environment. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test for XY', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'hidden_T_C3893', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'hidden_OWN_ID_123', + 'hidden_IMPL_01', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'hidden_T_5CCAA', + 'parent_needs': list([ + 'hidden_T_5CCAA', + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'HIDDEN', + 'sections': list([ + 'HIDDEN', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'implemented', + 'style': None, + 'tags': list([ + 'test', + 'user_interface', + 'python27', + 'hidden', + ]), + 'target_id': 'hidden_T_C3893', + 'template': None, + 'title': 'Test for XY', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'small2_TEST_03': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'small2_TEST_03', + 'created_at': '', + 'delete': False, + 'description': 'AAA', + 'docname': 'subdoc/filter', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'AAA', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'small2_TEST_03', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Filter', + 'sections': list([ + 'Filter', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + ]), + 'target_id': 'small2_TEST_03', + 'template': None, + 'title': 'AAA', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'small_TEST_02': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'small_TEST_02', + 'created_at': '', + 'delete': False, + 'description': 'small_TEST_02', + 'docname': 'subdoc/filter', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST_02 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'small_TEST_02', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Filter', + 'sections': list([ + 'Filter', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'test_02', + 'test', + ]), + 'target_id': 'small_TEST_02', + 'template': None, + 'title': 'TEST_02 DESCRIPTION', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'small_abs_path_TEST_02': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'small_abs_path_TEST_02', + 'created_at': '', + 'delete': False, + 'description': 'small_abs_path_TEST_02', + 'docname': 'subdoc/abs_path_import', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST_02 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'small_abs_path_TEST_02', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Absolute path import test', + 'sections': list([ + 'Absolute path import test', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'test_02', + 'test', + ]), + 'target_id': 'small_abs_path_TEST_02', + 'template': None, + 'title': 'TEST_02 DESCRIPTION', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'small_depr_rel_path_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'small_depr_rel_path_TEST_01', + 'created_at': '', + 'delete': False, + 'description': 'small_depr_rel_path_TEST_01', + 'docname': 'subdoc/deprecated_rel_path_import', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST_01 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'small_depr_rel_path_TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Deprecated Relative path import test', + 'sections': list([ + 'Deprecated Relative path import test', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'small_depr_rel_path_TEST_01', + 'template': None, + 'title': 'TEST_01 DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'small_rel_path_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'small_rel_path_TEST_01', + 'created_at': '', + 'delete': False, + 'description': 'small_rel_path_TEST_01', + 'docname': 'subdoc/rel_path_import', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST_01 DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'small_rel_path_TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Relative path import test', + 'sections': list([ + 'Relative path import test', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'small_rel_path_TEST_01', + 'template': None, + 'title': 'TEST_01 DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_IMPL_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_IMPL_01', + 'created_at': '', + 'delete': False, + 'description': 'Incoming links of this spec: :need_incoming:`test_IMPL_01`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Implementation for specification', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_IMPL_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'test_OWN_ID_123', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'imported', + 'new_tag', + ]), + 'target_id': 'test_IMPL_01', + 'template': None, + 'title': 'Implementation for specification', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_OWN_ID_123': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_OWN_ID_123', + 'created_at': '', + 'delete': False, + 'description': 'Outgoing links of this spec: :need_outgoing:`test_OWN_ID_123`.', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification of a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_OWN_ID_123', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'test_R_F4722', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'imported', + 'new_tag', + ]), + 'target_id': 'test_OWN_ID_123', + 'template': None, + 'title': 'Specification of a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_REQ_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_REQ_001', + 'created_at': '', + 'delete': False, + 'description': ''' + This is an awesome requirement and it includes a nice title, + a given id, a tag and this text as description. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_REQ_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'example', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_REQ_001', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_ROLES_REQ_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_ROLES_REQ_1', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Sliced Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_ROLES_REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'imported', + 'new_tag', + ]), + 'target_id': 'test_ROLES_REQ_1', + 'template': None, + 'title': 'Sliced Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_ROLES_REQ_2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_ROLES_REQ_2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Butter on Bread', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_ROLES_REQ_2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'test_ROLES_REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'imported', + 'new_tag', + ]), + 'target_id': 'test_ROLES_REQ_2', + 'template': None, + 'title': 'Butter on Bread', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_R_22EB2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_R_22EB2', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_R_22EB2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_R_22EB2', + 'template': None, + 'title': 'Requirement B', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_R_2A9D0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_R_2A9D0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_R_2A9D0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_R_2A9D0', + 'template': None, + 'title': 'Requirement A', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_R_F4722': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_R_F4722', + 'created_at': '', + 'delete': False, + 'description': ''' + This is my **first** requirement!! + + .. note:: You can use any rst code inside it :) + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'My first requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_R_F4722', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'requirement', + 'test', + 'awesome', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_R_F4722', + 'template': None, + 'title': 'My first requirement', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_S_01A67': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_S_01A67', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification B', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_S_01A67', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'B', + 'filter', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_S_01A67', + 'template': None, + 'title': 'Specification B', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_S_503A1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_S_503A1', + 'created_at': '', + 'delete': False, + 'description': ''' + We haven't set an **ID** here, so sphinxcontrib-needs + will generated one for us. + + But we have **set a link** to our first requirement and + also a *status* is given. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Spec for a requirement', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_S_503A1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'test_REQ_001', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'done', + 'style': None, + 'tags': list([ + 'important', + 'example', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_S_503A1', + 'template': None, + 'title': 'Spec for a requirement', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_S_D70B0': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_S_D70B0', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Specification A', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_S_D70B0', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'A', + 'filter', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_S_D70B0', + 'template': None, + 'title': 'Specification A', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_TEST_01': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_TEST_01', + 'created_at': '', + 'delete': False, + 'description': 'TEST IMPORT TITLE', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST IMPORT DESCRIPTION', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_TEST_01', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'imported', + 'new_tag', + ]), + 'target_id': 'test_TEST_01', + 'template': None, + 'title': 'TEST IMPORT DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_T_5CCAA': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'test_T_5CCAA', + 'created_at': '', + 'delete': False, + 'description': '', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_T_5CCAA', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + 'test_T_C3893', + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'awesome', + 'filter', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_T_5CCAA', + 'template': None, + 'title': 'Test 1', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'test_T_C3893': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': None, + 'created_at': '', + 'delete': False, + 'description': ''' + This test checks :need:`impl_01` for :need:`test_OWN_ID_123` inside a + Python 2.7 environment. + ''', + 'docname': 'index', + 'doctype': '', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test for XY', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'test_T_C3893', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'links': list([ + 'test_OWN_ID_123', + 'test_IMPL_01', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': 'test_T_5CCAA', + 'parent_needs': list([ + 'test_T_5CCAA', + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST', + 'sections': list([ + 'TEST', + 'TEST DOCUMENT IMPORT', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'implemented', + 'style': None, + 'tags': list([ + 'test', + 'user_interface', + 'python27', + 'imported', + 'new_tag', + ]), + 'target_id': 'test_T_C3893', + 'template': None, + 'title': 'Test for XY', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 63, + }), + }), + }) +# --- +# name: test_needimport_needs_json_download[test_app0] + dict({ + 'IMP_TEST_101': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'IMP_TEST_101 DESCRIPTION', + 'content_id': 'IMP_TEST_101', + 'created_at': '', + 'delete': False, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'TEST_101 TITLE', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'IMP_TEST_101', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': False, + 'layout': None, + 'lineno': 14, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + 'sections': list([ + 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'ext_test', + ]), + 'target_id': 'IMP_TEST_101', + 'template': None, + 'title': 'TEST_101 TITLE', + 'type': 'impl', + 'type_color': '#DF744A', + 'type_name': 'Implementation', + 'type_prefix': 'IM_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SPEC_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'other.', + 'content_id': 'SPEC_1', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'A Spec', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'SPEC_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 9, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + 'sections': list([ + 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SPEC_1', + 'template': None, + 'title': 'A Spec', + 'type': 'spec', + 'type_color': '#FEDCD2', + 'type_name': 'Specification', + 'type_prefix': 'SP_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'STORY_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'some.', + 'content_id': 'STORY_1', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'A story', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'STORY_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 4, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + 'sections': list([ + 'TEST DOCUMENT NEEDIMPORT DOWNLOAD NEEDS JSON', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'STORY_1', + 'template': None, + 'title': 'A story', + 'type': 'story', + 'type_color': '#BFD8D2', + 'type_name': 'User Story', + 'type_prefix': 'US_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }) +# --- diff --git a/tests/__snapshots__/test_need_constraints.ambr b/tests/__snapshots__/test_need_constraints.ambr new file mode 100644 index 000000000..8334cd384 --- /dev/null +++ b/tests/__snapshots__/test_need_constraints.ambr @@ -0,0 +1,611 @@ +# serializer version: 1 +# name: test_need_constraints[test_app0] + dict({ + 'current_version': '', + 'project': 'Python', + 'versions': dict({ + '': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'SECURITY_REQ': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'SECURITY_REQ', + 'created_at': '', + 'delete': None, + 'description': 'This is a requirement describing OPSEC processes.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'test1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SECURITY_REQ', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SECURITY_REQ', + 'template': None, + 'title': 'test1', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SP_109F4': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'critical', + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + 'critical': dict({ + 'check_0': True, + }), + }), + 'content_id': 'SP_109F4', + 'created_at': '', + 'delete': None, + 'description': 'Example of a successful constraint.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'test2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SP_109F4', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'SECURITY_REQ', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + 'critical', + ]), + 'target_id': 'SP_109F4', + 'template': None, + 'title': 'test2', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SP_3EBFA': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'critical', + ]), + 'constraints_error': 'need SP_3EBFA does not fulfill CRITICAL constraint, because tags are []', + 'constraints_passed': False, + 'constraints_results': dict({ + 'critical': dict({ + 'check_0': False, + }), + }), + 'content_id': 'SP_3EBFA', + 'created_at': '', + 'delete': None, + 'description': 'Example of a failed constraint.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'test3', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SP_3EBFA', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': 'debug', + 'links': list([ + 'SECURITY_REQ', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': 'red_bar', + 'tags': list([ + ]), + 'target_id': 'SP_3EBFA', + 'template': None, + 'title': 'test3', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SP_CA3FB': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'team', + ]), + 'constraints_passed': False, + 'constraints_results': dict({ + 'team': dict({ + 'check_0': False, + }), + }), + 'content_id': 'SP_CA3FB', + 'created_at': '', + 'delete': None, + 'description': 'Example of a failed constraint with medium severity. Note the style from :ref:`needs_constraint_failed_options`', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'FAIL_01', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SP_CA3FB', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': 'yellow_bar,', + 'tags': list([ + ]), + 'target_id': 'SP_CA3FB', + 'template': None, + 'title': 'FAIL_01', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SP_TOO_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'SP_TOO_001', + 'created_at': '', + 'delete': None, + 'description': 'The Tool awesome shall have a command line interface.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Command line interface', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SP_TOO_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'implemented', + 'style': None, + 'tags': list([ + 'test', + 'test2', + ]), + 'target_id': 'SP_TOO_001', + 'template': None, + 'title': 'Command line interface', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SP_TOO_002': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'critical', + ]), + 'constraints_error': "need SP_TOO_002 does not fulfill CRITICAL constraint, because tags are ['hello', 'there']", + 'constraints_passed': False, + 'constraints_results': dict({ + 'critical': dict({ + 'check_0': False, + }), + }), + 'content_id': 'SP_TOO_002', + 'created_at': '', + 'delete': None, + 'description': 'asdf', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'CLI', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'SP_TOO_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'dev', + 'style': 'red_bar', + 'tags': list([ + 'hello', + 'there', + ]), + 'target_id': 'SP_TOO_002', + 'template': None, + 'title': 'CLI', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_STYLE': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'critical', + ]), + 'constraints_error': 'need TEST_STYLE does not fulfill CRITICAL constraint, because tags are []', + 'constraints_passed': False, + 'constraints_results': dict({ + 'critical': dict({ + 'check_0': False, + }), + }), + 'content_id': 'TEST_STYLE', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'style_test', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'CLI', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_STYLE', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': 'red_bar', + 'tags': list([ + ]), + 'target_id': 'TEST_STYLE', + 'template': None, + 'title': 'CLI', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TEST_STYLE2': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + 'team', + ]), + 'constraints_passed': False, + 'constraints_results': dict({ + 'team': dict({ + 'check_0': False, + }), + }), + 'content_id': 'TEST_STYLE2', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'style_test', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'CLI2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TEST_STYLE2', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS CONSTRAINTS', + 'sections': list([ + 'TEST DOCUMENT NEEDS CONSTRAINTS', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': 'blue_border, yellow_bar', + 'tags': list([ + ]), + 'target_id': 'TEST_STYLE2', + 'template': None, + 'title': 'CLI2', + 'type': 'spec', + 'type_name': 'Specification', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 8, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_needarch.ambr b/tests/__snapshots__/test_needarch.ambr new file mode 100644 index 000000000..40c879713 --- /dev/null +++ b/tests/__snapshots__/test_needarch.ambr @@ -0,0 +1,77 @@ +# serializer version: 1 +# name: test_doc_needarch_jinja_import[test_app0] + dict({ + 'needarch-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: hi Alice + + {{import("uses", "tests")}} + ''', + 'content_calculated': ''' + @startuml + + Alice -> Bob: Hi Bob + Bob --> Alice: hi Alice + + node "<size:12>User Story</size>\n**Story**\n<size:10>US_001</size>" as US_001 [[../index.html#US_001]] #BFD8D2 + node "<size:12>User Story</size>\n**Story 002**\n<size:10>US_002</size>" as US_002 [[../index.html#US_002]] #BFD8D2 + card "<size:12>Interface</size>\n**Test interface**\n<size:10>INT_001</size>" as INT_001 [[../index.html#INT_001]] #BFD8D2 + card "<size:12>Interface</size>\n**Test interface2**\n<size:10>INT_002</size>" as INT_002 [[../index.html#INT_002]] #BFD8D2 + + @enduml + + ''', + 'debug': True, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': True, + 'key': None, + 'lineno': 3, + 'save': None, + 'scale': '50', + 'target_id': 'needarch-index-0', + }), + }) +# --- +# name: test_needarch_jinja_func_need[test_app0] + dict({ + 'needarch-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + {{flow(need().id)}} + ''', + 'content_calculated': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + card "<size:12>Interface</size>\n**Test needuml**\n**jinja func need**\n<size:10>INT_001</size>" as INT_001 [[../index.html#INT_001]] #BFD8D2 + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': True, + 'key': None, + 'lineno': 1, + 'save': None, + 'scale': '', + 'target_id': 'needarch-index-0', + }), + }) +# --- diff --git a/tests/__snapshots__/test_needextend.ambr b/tests/__snapshots__/test_needextend.ambr new file mode 100644 index 000000000..ca3a866b5 --- /dev/null +++ b/tests/__snapshots__/test_needextend.ambr @@ -0,0 +1,455 @@ +# serializer version: 1 +# name: test_doc_needextend_html[test_app0] + dict({ + 'current_version': '', + 'project': 'Python', + 'versions': dict({ + '': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'extend_test_003': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_003', + 'created_at': '', + 'delete': None, + 'description': ''' + Had no outgoing links. + Got an outgoing link ``extend_test_004``. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend Example 3', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_003', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'extend_test_004', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 1, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Need extend', + 'sections': list([ + 'Need extend', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'extend_test_003', + 'template': None, + 'title': 'needextend Example 3', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'extend_test_004': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_004', + 'created_at': '', + 'delete': None, + 'description': ''' + Had no links. + Got an incoming links ``extend_test_003`` and ``extend_test_006``. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend Example 4', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_004', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Need extend', + 'sections': list([ + 'Need extend', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'extend_test_004', + 'template': None, + 'title': 'needextend Example 4', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'extend_test_005': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_005', + 'created_at': '', + 'delete': None, + 'description': ''' + Had the two links: ``extend_test_003`` and ``extend_test_004``. + Both got deleted. + ''', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend Example 5', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_005', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 1, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Need extend', + 'sections': list([ + 'Need extend', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'extend_test_005', + 'template': None, + 'title': 'needextend Example 5', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'extend_test_006': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_006', + 'created_at': '', + 'delete': None, + 'description': 'Had the link ``extend_test_003``, got another one ``extend_test_004``.', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend Example 6', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_006', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'extend_test_003', + 'extend_test_004', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 2, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Need extend', + 'sections': list([ + 'Need extend', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'extend_test_006', + 'template': None, + 'title': 'needextend Example 6', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'extend_test_007': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_007', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend Example 7', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_007', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'extend_test_003', + 'extend_test_004', + 'extend_test_005', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 1, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'Need extend', + 'sections': list([ + 'Need extend', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'extend_test_007', + 'template': None, + 'title': 'needextend Example 7', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'extend_test_page': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'extend_test_page', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'page_1', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'needextend different pages test', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'extend_test_page', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 2, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'need objects', + 'sections': list([ + 'need objects', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + 'tag_1', + 'new_tag', + 'another_tag', + ]), + 'target_id': 'extend_test_page', + 'template': None, + 'title': 'needextend different pages test', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 6, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_needs_builder.ambr b/tests/__snapshots__/test_needs_builder.ambr new file mode 100644 index 000000000..e3cf93b71 --- /dev/null +++ b/tests/__snapshots__/test_needs_builder.ambr @@ -0,0 +1,397 @@ +# serializer version: 1 +# name: test_doc_needs_builder[test_app0] + dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'TC_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TC_001', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test example', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TC_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS Builder', + 'sections': list([ + 'TEST DOCUMENT NEEDS Builder', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TC_001', + 'template': None, + 'title': 'Test example', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'TC_NEG_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'TC_NEG_001', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Negative test example', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'TC_NEG_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS Builder', + 'sections': list([ + 'TEST DOCUMENT NEEDS Builder', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'closed', + 'style': None, + 'tags': list([ + ]), + 'target_id': 'TC_NEG_001', + 'template': None, + 'title': 'Negative test example', + 'type': 'test', + 'type_name': 'Test Case', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'US_63252': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'US_63252', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'A story', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'US_63252', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDS Builder', + 'sections': list([ + 'TEST DOCUMENT NEEDS Builder', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'in progress', + 'style': None, + 'tags': list([ + '1', + ]), + 'target_id': 'US_63252', + 'template': None, + 'title': 'A story', + 'type': 'story', + 'type_name': 'User Story', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 3, + }), + '2.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + 'TEST_01': dict({ + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'created_at': '', + 'description': 'TEST_01', + 'docname': 'index', + 'duration': '', + 'external_css': 'external_link', + 'external_url': 'file:///home/daniel/workspace/sphinx/sphinxcontrib-needs/tests/doc_test/external_doc/__error__#TEST_01', + 'full_title': 'TEST_01 DESCRIPTION', + 'hidden': '', + 'id': 'TEST_01', + 'id_complete': 'TEST_01', + 'id_parent': 'TEST_01', + 'id_prefix': '', + 'is_external': True, + 'is_need': True, + 'is_part': False, + 'layout': None, + 'links': list([ + 'SPEC_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'parent_need': None, + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'query': '', + 'section_name': '', + 'sections': list([ + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'template': None, + 'title': 'TEST_01 DESCRIPTION', + 'type': 'impl', + 'type_name': 'Implementation', + 'updated_at': '', + 'url': '', + 'user': '', + }), + 'TEST_02': dict({ + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'created_at': '', + 'description': 'TEST_02', + 'docname': 'index', + 'duration': '', + 'external_css': 'external_link', + 'external_url': 'file:///home/daniel/workspace/sphinx/sphinxcontrib-needs/tests/doc_test/external_doc/__error__#TEST_02', + 'full_title': 'TEST_02 DESCRIPTION', + 'hidden': '', + 'id': 'TEST_02', + 'id_complete': 'TEST_02', + 'id_parent': 'TEST_02', + 'id_prefix': '', + 'is_external': True, + 'is_need': True, + 'is_part': False, + 'layout': None, + 'links': list([ + 'TEST_01', + 'REQ_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'parent_need': None, + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'query': '', + 'section_name': '', + 'sections': list([ + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + 'test_02', + 'test', + ]), + 'template': None, + 'title': 'TEST_02 DESCRIPTION', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'user': '', + }), + 'TEST_03': dict({ + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'created_at': '', + 'description': 'AAA', + 'docname': 'subpage_a/subpage_b/subpage', + 'duration': '', + 'external_css': 'external_link', + 'external_url': 'file:///home/daniel/workspace/sphinx/sphinxcontrib-needs/tests/doc_test/external_doc/__error__#TEST_03', + 'full_title': 'AAA', + 'hidden': '', + 'id': 'TEST_03', + 'id_complete': 'TEST_03', + 'id_parent': 'TEST_03', + 'id_prefix': '', + 'is_external': True, + 'is_need': True, + 'is_part': False, + 'layout': None, + 'links': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'parent_need': None, + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'query': '', + 'section_name': '', + 'sections': list([ + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': 'open', + 'style': None, + 'tags': list([ + ]), + 'template': None, + 'title': 'AAA', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'user': '', + }), + }), + 'needs_amount': 6, + }), + }), + }) +# --- diff --git a/tests/__snapshots__/test_needuml.ambr b/tests/__snapshots__/test_needuml.ambr new file mode 100644 index 000000000..a17713037 --- /dev/null +++ b/tests/__snapshots__/test_needuml.ambr @@ -0,0 +1,1334 @@ +# serializer version: 1 +# name: test_doc_build_html[test_app0] + dict({ + 'COMP_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + class "test component" as comp { + name + functions + activate() + } + + {{uml("INT_001")}} + + comp --> int + ''', + 'content_id': 'COMP_001', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test component', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'COMP_001', + 'id_complete': 'COMP_001', + 'id_parent': 'COMP_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 19, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'COMP_001', + 'template': None, + 'title': 'Test component', + 'type': 'comp', + 'type_color': '#BFD8D2', + 'type_name': 'Component', + 'type_prefix': 'C_', + 'type_style': 'card', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'INT_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'circle "Int_X" as int', + 'content_id': 'INT_001', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test interface', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'INT_001', + 'id_complete': 'INT_001', + 'id_parent': 'INT_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 14, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'INT_001', + 'template': None, + 'title': 'Test interface', + 'type': 'int', + 'type_color': '#BFD8D2', + 'type_name': 'Interface', + 'type_prefix': 'I_', + 'type_style': 'card', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'INT_002': dict({ + 'arch': dict({ + 'diagram': ''' + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + ''', + 'sequence': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + .. needuml:: + :scale: 50% + :align: center + :config: mixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + + .. needuml:: + :scale: 50% + :align: center + :config: mixing + :key: sequence + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_id': 'INT_002', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test interface2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'INT_002', + 'id_complete': 'INT_002', + 'id_parent': 'INT_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 70, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'INT_002', + 'template': None, + 'title': 'Test interface2', + 'type': 'int', + 'type_color': '#BFD8D2', + 'type_name': 'Interface', + 'type_prefix': 'I_', + 'type_style': 'card', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'INT_003': dict({ + 'arch': dict({ + 'class': ''' + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("INT_002", "sequence")}} + ''', + 'sequence': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + .. needuml:: + :key: class + + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("INT_002", "sequence")}} + + .. needuml:: + :key: sequence + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_id': 'INT_003', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test interface3', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'INT_003', + 'id_complete': 'INT_003', + 'id_parent': 'INT_003', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 95, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'INT_003', + 'template': None, + 'title': 'Test interface3', + 'type': 'int', + 'type_color': '#BFD8D2', + 'type_name': 'Interface', + 'type_prefix': 'I_', + 'type_style': 'card', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'INT_004': dict({ + 'arch': dict({ + 'class': ''' + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + ''', + 'diagram': ''' + Superman -> Batman: Hi Bruce + Batman --> Superman: Hi Clark + ''', + 'sequence': ''' + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + ''', + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + .. needuml:: + :scale: 50% + :key: class + + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + + .. needuml:: + + Superman -> Batman: Hi Bruce + Batman --> Superman: Hi Clark + + .. needuml:: + :key: sequence + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + .. needuml:: + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_id': 'INT_004', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test interface4', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'INT_004', + 'id_complete': 'INT_004', + 'id_parent': 'INT_004', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 117, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'INT_004', + 'template': None, + 'title': 'Test interface4', + 'type': 'int', + 'type_color': '#BFD8D2', + 'type_name': 'Interface', + 'type_prefix': 'I_', + 'type_style': 'card', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'PROD_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + allowmixing + {{uml("SYS_001")}} + + node "System A" as sys_2 + sys_2 --> int + ''', + 'content_id': 'PROD_001', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test Product', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'PROD_001', + 'id_complete': 'PROD_001', + 'id_parent': 'PROD_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 46, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'PROD_001', + 'template': None, + 'title': 'Test Product', + 'type': 'prod', + 'type_color': '#FF68D2', + 'type_name': 'Product', + 'type_prefix': 'P_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'ST_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'Some content', + 'content_id': 'ST_001', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test story', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'ST_001', + 'id_complete': 'ST_001', + 'id_parent': 'ST_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 4, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'ST_001', + 'template': None, + 'title': 'Test story', + 'type': 'story', + 'type_color': '#BFD8D2', + 'type_name': 'User Story', + 'type_prefix': 'US_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'ST_002': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': 'Some content 2', + 'content_id': 'ST_002', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test story2', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'ST_002', + 'id_complete': 'ST_002', + 'id_parent': 'ST_002', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 9, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'ST_002', + 'template': None, + 'title': 'Test story2', + 'type': 'story', + 'type_color': '#BFD8D2', + 'type_name': 'User Story', + 'type_prefix': 'US_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'SYS_001': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'collapse': None, + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content': ''' + {{uml("COMP_001")}} + + class "Component 2" as comp_2 { + name + street + } + + comp_2 --> int + ''', + 'content_id': 'SYS_001', + 'created_at': '', + 'delete': None, + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Test System', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'hide': False, + 'id': 'SYS_001', + 'id_complete': 'SYS_001', + 'id_parent': 'SYS_001', + 'id_prefix': '', + 'is_external': False, + 'is_modified': False, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'lineno': 33, + 'links': list([ + ]), + 'links_back': list([ + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 0, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parent_needs_back': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'TEST DOCUMENT NEEDUML', + 'sections': list([ + 'TEST DOCUMENT NEEDUML', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'SYS_001', + 'template': None, + 'title': 'Test System', + 'type': 'sys', + 'type_color': '#FF68D2', + 'type_name': 'System', + 'type_prefix': 'S_', + 'type_style': 'node', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }) +# --- +# name: test_doc_build_html[test_app0].1 + dict({ + 'needuml-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': ''' + + allowmixing + + ''', + 'config_names': 'mixing', + 'content': ''' + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + ''', + 'content_calculated': ''' + @startuml + + ' Config + + allowmixing + + + class "Test story" as test { + implement + None + } + + node "<size:12>System</size>\n**Test System**\n<size:10>SYS_001</size>" as SYS_001 [[../index.html#SYS_001]] #FF68D2 + @enduml + + ''', + 'debug': True, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 56, + 'save': None, + 'scale': '50', + 'target_id': 'needuml-index-0', + }), + 'needuml-index-1': dict({ + 'align': 'center', + 'caption': None, + 'config': ''' + + allowmixing + + ''', + 'config_names': 'mixing', + 'content': ''' + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + ''', + 'content_calculated': ''' + @startuml + + ' Config + + allowmixing + + + class "Test story" as test { + implement + None + } + + node "<size:12>System</size>\n**Test System**\n<size:10>SYS_001</size>" as SYS_001 [[../index.html#SYS_001]] #FF68D2 + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 1, + 'save': None, + 'scale': '50', + 'target_id': 'needuml-index-1', + }), + 'needuml-index-2': dict({ + 'align': 'center', + 'caption': None, + 'config': ''' + + allowmixing + + ''', + 'config_names': 'mixing', + 'content': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_calculated': ''' + @startuml + + ' Config + + allowmixing + + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': 'sequence', + 'lineno': 13, + 'save': None, + 'scale': '50', + 'target_id': 'needuml-index-2', + }), + 'needuml-index-3': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("INT_002", "sequence")}} + ''', + 'content_calculated': ''' + @startuml + + allowmixing + + class "Test story" as test { + implement + None + } + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': 'class', + 'lineno': 1, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-3', + }), + 'needuml-index-4': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_calculated': ''' + @startuml + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': 'sequence', + 'lineno': 13, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-4', + }), + 'needuml-index-5': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + allowmixing + + class "{{needs['ST_001'].title}}" as test { + implement + {{needs['ST_001'].status}} + } + + {{uml("SYS_001")}} + ''', + 'content_calculated': ''' + @startuml + + allowmixing + + class "Test story" as test { + implement + None + } + + node "<size:12>System</size>\n**Test System**\n<size:10>SYS_001</size>" as SYS_001 [[../index.html#SYS_001]] #FF68D2 + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': 'class', + 'lineno': 1, + 'save': None, + 'scale': '50', + 'target_id': 'needuml-index-5', + }), + 'needuml-index-6': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + Superman -> Batman: Hi Bruce + Batman --> Superman: Hi Clark + ''', + 'content_calculated': ''' + @startuml + + Superman -> Batman: Hi Bruce + Batman --> Superman: Hi Clark + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 14, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-6', + }), + 'needuml-index-7': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + ''', + 'content_calculated': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': 'sequence', + 'lineno': 19, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-7', + }), + 'needuml-index-8': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + ''', + 'content_calculated': ''' + @startuml + + Alice -> Bob: Hi Bob + Bob --> Alice: Hi Alice + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 25, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-8', + }), + }) +# --- +# name: test_needuml_filter[test_app0] + dict({ + 'needuml-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + {% for need in filter("type == 'story' and status != 'open'") %} + {{uml(need.id)}} + {% endfor %} + ''', + 'content_calculated': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + + node "<size:12>User Story</size>\n**Test story 02**\n<size:10>ST_002</size>" as ST_002 [[../index.html#ST_002]] #BFD8D2 + + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 1, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-0', + }), + }) +# --- +# name: test_needuml_jinja_func_flow[test_app0] + dict({ + 'needuml-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + {{flow("ST_001")}} + ''', + 'content_calculated': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + + node "<size:12>User Story</size>\n**Test story**\n<size:10>ST_001</size>" as ST_001 [[../index.html#ST_001]] #BFD8D2 + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 1, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-0', + }), + }) +# --- +# name: test_needuml_jinja_func_ref[test_app0] + dict({ + 'needuml-index-0': dict({ + 'align': 'center', + 'caption': None, + 'config': '', + 'config_names': None, + 'content': ''' + DC -> Marvel: {{ref("ST_001", option="title")}} + Marvel --> DC: {{ref("ST_002", text="Different text to explain the story")}} + ''', + 'content_calculated': ''' + @startuml + + DC -> Marvel: [[../index.html#ST_001 Test story]] + Marvel --> DC: [[../index.html#ST_002 Different text to explain the story]] + @enduml + + ''', + 'debug': False, + 'docname': 'index', + 'extra': dict({ + }), + 'is_arch': False, + 'key': None, + 'lineno': 1, + 'save': None, + 'scale': '', + 'target_id': 'needuml-index-0', + }), + }) +# --- +# name: test_needuml_save[test_app0] + dict({ + 'uml1': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + @enduml + + ''', + 'uml2': ''' + @startuml + + node "<size:12>User Story</size>\n**Test story**\n<size:10>ST_001</size>" as ST_001 [[../index.html#ST_001]] #BFD8D2 + node "<size:12>User Story</size>\n**Test story 2**\n<size:10>ST_002</size>" as ST_002 [[../index.html#ST_002]] #BFD8D2 + @enduml + + ''', + }) +# --- +# name: test_needumls_builder[test_app0] + dict({ + 'uml1': ''' + @startuml + + DC -> Marvel: Hi Kevin + Marvel --> DC: Anyone there? + @enduml + + ''', + 'uml2': ''' + @startuml + + node "<size:12>User Story</size>\n**Test story**\n<size:10>ST_001</size>" as ST_001 [[../#ST_001]] #BFD8D2 + node "<size:12>User Story</size>\n**Test story 2**\n<size:10>ST_002</size>" as ST_002 [[../#ST_002]] #BFD8D2 + @enduml + + ''', + }) +# --- diff --git a/tests/conftest.py b/tests/conftest.py index 681b756e1..c620eabcc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -3,7 +3,9 @@ from tempfile import mkdtemp import pytest +from docutils.nodes import document from sphinx.testing.path import path +from syrupy.extensions.single_file import SingleFileSnapshotExtension, WriteMode pytest_plugins = "sphinx.testing.fixtures" @@ -48,3 +50,29 @@ def test_app(make_app, request): # cleanup test temporary directory shutil.rmtree(sphinx_test_tempdir, False) + + +class DoctreeSnapshotExtension(SingleFileSnapshotExtension): + _write_mode = WriteMode.TEXT + _file_extension = "doctree.xml" + + def serialize(self, data, **kwargs): + if not isinstance(data, document): + raise TypeError(f"Expected document, got {type(data)}") + doc = data.deepcopy() + doc["source"] = "<source>" # this will be a temp path + doc.attributes.pop("translation_progress", None) # added in sphinx 7.1 + return doc.pformat() + + +@pytest.fixture +def snapshot_doctree(snapshot): + """Snapshot fixture for doctrees. + + Here we try to sanitize the doctree, to make the snapshots reproducible. + """ + try: + return snapshot.with_defaults(extension_class=DoctreeSnapshotExtension) + except AttributeError: + # fallback for older versions of pytest-snapshot + return snapshot.use_extension(DoctreeSnapshotExtension) diff --git a/tests/doc_test/doc_basic/index.rst b/tests/doc_test/doc_basic/index.rst index cc41e8947..539ca0693 100644 --- a/tests/doc_test/doc_basic/index.rst +++ b/tests/doc_test/doc_basic/index.rst @@ -1,16 +1,6 @@ -.. basic test documentation master file, created by - sphinx-quickstart on Thu May 19 21:05:52 2022. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. - Welcome to basic test's documentation! ====================================== -.. toctree:: - :maxdepth: 2 - :caption: Contents: - - .. story:: Test story :id: ST_001 :status: open @@ -21,12 +11,3 @@ Welcome to basic test's documentation! .. needtable:: :filter: status == "open" - - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/tests/doc_test/doc_needextend/conf.py b/tests/doc_test/doc_needextend/conf.py index 4e7116d36..7f111502f 100644 --- a/tests/doc_test/doc_needextend/conf.py +++ b/tests/doc_test/doc_needextend/conf.py @@ -2,6 +2,7 @@ extensions = ["sphinx_needs"] +needs_build_json = True needs_id_regex = "^[A-Za-z0-9_]*" needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, diff --git a/tests/doc_test/need_constraints/conf.py b/tests/doc_test/need_constraints/conf.py index a2a50da0b..acbee6adf 100644 --- a/tests/doc_test/need_constraints/conf.py +++ b/tests/doc_test/need_constraints/conf.py @@ -2,6 +2,7 @@ extensions = ["sphinx_needs"] +needs_build_json = True needs_table_style = "TABLE" needs_types = [ @@ -54,11 +55,14 @@ def setup(app): needs_extra_options = [] - needs_constraints = { "security": {"check_0": "'security' in tags", "severity": "CRITICAL"}, "team": {"check_0": "'team_requirement' in links", "severity": "MEDIUM"}, - "critical": {"check_0": "'critical' in tags", "severity": "CRITICAL"}, + "critical": { + "check_0": "'critical' in tags", + "severity": "CRITICAL", + "error_message": "need {{id}} does not fulfill CRITICAL constraint, because tags are {{tags}}", + }, } diff --git a/tests/test_api_configuration.py b/tests/test_api_configuration.py index b6ab5dce4..556c98887 100644 --- a/tests/test_api_configuration.py +++ b/tests/test_api_configuration.py @@ -21,29 +21,18 @@ def test_api_get_types(test_app): app = test_app need_types = get_need_types(app) - assert "story" in need_types - assert "req" not in need_types + assert set(need_types) == {"story", "spec", "impl", "test"} @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/api_doc_awesome"}], indirect=True) -def test_api_add_type(test_app): +def test_api_add_type(test_app, snapshot): from sphinx_needs.api import add_need_type app = test_app add_need_type(app, "awesome", "Awesome", "AW_", "#000000", "cloud") need_types = app.config.needs_types - assert len(need_types) == 5 - found = False - for need_type in need_types: - if need_type["directive"] == "awesome": - found = True - assert need_type["title"] == "Awesome" - assert need_type["prefix"] == "AW_" - assert need_type["color"] == "#000000" - assert need_type["style"] == "cloud" - - assert found + assert need_types == snapshot app.builder.build_all() html = Path(app.outdir, "index.html").read_text() diff --git a/tests/test_basic_doc.py b/tests/test_basic_doc.py index 4e47fa1c7..5a1735725 100644 --- a/tests/test_basic_doc.py +++ b/tests/test_basic_doc.py @@ -9,7 +9,8 @@ import pytest import responses -import sphinx.application +from sphinx.application import Sphinx +from syrupy.filters import props from sphinx_needs.api.need import NeedsNoIdException from tests.data.service_github import ( @@ -69,7 +70,7 @@ def test_build_html(test_app): @responses.activate @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/generic_doc"}], indirect=True) -def test_build_html_parallel(test_app): +def test_build_html_parallel(test_app: Sphinx, snapshot_doctree): responses.add_callback( responses.GET, re.compile(r"https://api.github.com/.*"), @@ -88,6 +89,8 @@ def test_build_html_parallel(test_app): assert build_dir / "datatables_loader.js" in files assert build_dir / "DataTables-1.10.16" / "js" / "jquery.dataTables.min.js" in files + assert app.env.get_doctree("index") == snapshot_doctree + @pytest.mark.skipif(sys.platform == "win32", reason="assert fails on windows, need to fix later.") @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/generic_doc"}], indirect=True) @@ -176,7 +179,7 @@ def test_build_json(test_app): @responses.activate @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/doc_basic"}], indirect=True) -def test_build_needs(test_app): +def test_build_needs(test_app, snapshot): responses.add_callback( responses.GET, re.compile(r"https://api.github.com/.*"), @@ -190,27 +193,7 @@ def test_build_needs(test_app): json_text = Path(app.outdir, "needs.json").read_text() needs_data = json.loads(json_text) - # Validate top-level data - assert "created" in needs_data - assert "project" in needs_data - assert "versions" in needs_data - assert "current_version" in needs_data - current_version = needs_data["current_version"] - assert current_version == app.config.version - - # Validate current version data - current_version_data = needs_data["versions"][current_version] - assert "created" in current_version_data - assert "needs" in current_version_data - assert "needs_amount" in current_version_data - assert "needs_amount" in current_version_data - assert current_version_data["needs_amount"] == len(current_version_data["needs"]) - - # Validate individual needs data - current_needs = current_version_data["needs"] - expected_keys = ("description", "id", "links", "sections", "status", "tags", "title", "type_name") - for need in current_needs.values(): - assert all(key in need for key in expected_keys) + assert needs_data == snapshot(exclude=props("created")) # Test with needs_id_required=True and missing ids in docs. @@ -251,7 +234,7 @@ def test_sphinx_api_build(): temp_dir = tempfile.mkdtemp() src_dir = os.path.join(os.path.dirname(__file__), "doc_test", "doc_basic") - sphinx_app = sphinx.application.Sphinx( + sphinx_app = Sphinx( srcdir=src_dir, confdir=src_dir, outdir=temp_dir, diff --git a/tests/test_export_id.py b/tests/test_export_id.py index 6b328a945..dcdb7152e 100644 --- a/tests/test_export_id.py +++ b/tests/test_export_id.py @@ -3,21 +3,15 @@ from pathlib import Path import pytest +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/doc_export_id"}], indirect=True) -def test_export_id(test_app): +def test_export_id(test_app, snapshot): app = test_app app.build() - content = Path(app.outdir, "needs.json").read_text() - assert "filters" in content - - content_obj = json.loads(content) - assert content_obj is not None - assert "created" in content_obj - assert "FLOW_1" in content_obj["versions"]["1.0"]["filters"] - assert "TABLE_1" in content_obj["versions"]["1.0"]["filters"] - assert "LIST_1" in content_obj["versions"]["1.0"]["filters"] + needs_data = json.loads(Path(app.outdir, "needs.json").read_text()) + assert needs_data == snapshot(exclude=props("created")) @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_export_id"}], indirect=True) diff --git a/tests/test_external.py b/tests/test_external.py index 519b0df9b..9169cf431 100644 --- a/tests/test_external.py +++ b/tests/test_external.py @@ -2,6 +2,7 @@ from pathlib import Path import pytest +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/external_doc"}], indirect=True) @@ -21,15 +22,12 @@ def test_external_html(test_app): @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/external_doc"}], indirect=True) -def test_external_json(test_app): +def test_external_json(test_app, snapshot): app = test_app app.build() json_data = Path(app.outdir, "needs.json").read_text() needs = json.loads(json_data) - external_need = needs["versions"]["1.0"]["needs"]["EXT_TEST_01"] - assert external_need["external_url"] == "http://my_company.com/docs/v1/index.html#TEST_01" - assert external_need["external_css"] == "external_link" - assert external_need["is_external"] is True + assert needs == snapshot(exclude=props("created")) @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/external_doc"}], indirect=True) diff --git a/tests/test_import.py b/tests/test_import.py index 1193c255f..e5bd1b760 100644 --- a/tests/test_import.py +++ b/tests/test_import.py @@ -3,6 +3,7 @@ import pytest import requests_mock +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/import_doc"}], indirect=True) @@ -97,38 +98,18 @@ def test_import_non_exists_json(test_app): @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/import_doc"}], indirect=True) -def test_import_builder(test_app): +def test_import_builder(test_app, snapshot): app = test_app app.build() needs_text = Path(app.outdir, "needs.json").read_text() needs = json.loads(needs_text) - assert "created" in needs - need = needs["versions"]["1.0"]["needs"]["REQ_1"] - - check_keys = [ - "id", - "type", - "description", - "full_title", - "is_need", - "is_part", - "links", - "section_name", - "status", - "tags", - "title", - "type_name", - ] - - for key in check_keys: - if key not in need.keys(): - raise AssertionError("%s not in exported need" % key) + assert needs == snapshot(exclude=props("created")) @pytest.mark.parametrize( "test_app", [{"buildername": "needs", "srcdir": "doc_test/doc_needimport_download_needs_json"}], indirect=True ) -def test_needimport_needs_json_download(test_app): +def test_needimport_needs_json_download(test_app, snapshot): app = test_app # Mock requests @@ -189,14 +170,7 @@ def test_needimport_needs_json_download(test_app): app.build() needs_all_needs = app.env.needs_all_needs - assert len(needs_all_needs) == 3 - - # check import needs from needs.json - assert "IMP_TEST_101" in needs_all_needs - - imported_need = remote_json["versions"]["1.0"]["needs"]["TEST_101"] - assert needs_all_needs["IMP_TEST_101"]["tags"] == imported_need["tags"] - assert needs_all_needs["IMP_TEST_101"]["title"] == imported_need["title"] + assert needs_all_needs == snapshot(exclude=props("content_node")) @pytest.mark.parametrize( diff --git a/tests/test_need_constraints.py b/tests/test_need_constraints.py index f55f2fe95..72e869dfa 100644 --- a/tests/test_need_constraints.py +++ b/tests/test_need_constraints.py @@ -1,16 +1,22 @@ +import json import subprocess from pathlib import Path import pytest +from syrupy.filters import props from sphinx_needs.api.exceptions import NeedsConstraintNotAllowed @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/need_constraints"}], indirect=True) -def test_need_constraints(test_app): +def test_need_constraints(test_app, snapshot): app = test_app app.build() + json_text = Path(app.outdir, "needs.json").read_text() + needs_data = json.loads(json_text) + assert needs_data == snapshot(exclude=props("created")) + srcdir = Path(app.srcdir) out_dir = srcdir / "_build" diff --git a/tests/test_needarch.py b/tests/test_needarch.py index 574ae5951..b75dfab13 100644 --- a/tests/test_needarch.py +++ b/tests/test_needarch.py @@ -34,7 +34,7 @@ def test_doc_needarch_negative(test_app): @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needarch_jinja_func_import"}], indirect=True ) -def test_doc_needarch_jinja_import(test_app): +def test_doc_needarch_jinja_import(test_app, snapshot): app = test_app app.build() html = Path(app.outdir, "index.html").read_text(encoding="utf8") @@ -42,43 +42,18 @@ def test_doc_needarch_jinja_import(test_app): # check needarch all_needumls = app.env.needs_all_needumls - assert len(all_needumls) == 1 - - need_arch = all_needumls["needarch-index-0"] - assert need_arch["is_arch"] - assert need_arch["content"] == 'Alice -> Bob: Hi Bob\nBob --> Alice: hi Alice\n\n{{import("uses", "tests")}}' - - assert need_arch["content_calculated"] - assert "@startuml\n\nAlice -> Bob: Hi Bob\n" in need_arch["content_calculated"] - assert ( - 'node "<size:12>User Story</size>\\n**Story**\\n<size:10>US_001</size>" as US_001 [[../index.html#US_001]] #BFD8D2\n' - in need_arch["content_calculated"] - ) - assert ( - 'node "<size:12>User Story</size>\\n**Story 002**\\n<size:10>US_002</size>" as US_002' - in need_arch["content_calculated"] - ) - assert ( - 'card "<size:12>Interface</size>\\n**Test interface**\\n<size:10>INT_001</size>" as INT_001' - in need_arch["content_calculated"] - ) - assert ( - 'card "<size:12>Interface</size>\\n**Test interface2**\\n<size:10>INT_002</size>" as INT_002' - in need_arch["content_calculated"] - ) + assert all_needumls == snapshot @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needarch_jinja_func_need"}], indirect=True ) -def test_needarch_jinja_func_need(test_app): +def test_needarch_jinja_func_need(test_app, snapshot): app = test_app app.build() all_needumls = app.env.needs_all_needumls - assert len(all_needumls) == 1 - - assert "{{flow(need().id)}}" in all_needumls["needarch-index-0"]["content"] + assert all_needumls == snapshot html = Path(app.outdir, "index.html").read_text(encoding="utf8") assert "as INT_001 [[../index.html#INT_001]]" in html diff --git a/tests/test_needextend.py b/tests/test_needextend.py index 19f9ae54d..0751f87d0 100644 --- a/tests/test_needextend.py +++ b/tests/test_needextend.py @@ -1,13 +1,20 @@ +import json import sys from pathlib import Path import pytest +from sphinx.application import Sphinx +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needextend"}], indirect=True) -def test_doc_needextend_html(test_app): +def test_doc_needextend_html(test_app: Sphinx, snapshot): app = test_app app.build() + + needs_data = json.loads(Path(app.outdir, "needs.json").read_text()) + assert needs_data == snapshot(exclude=props("created")) + index_html = Path(app.outdir, "index.html").read_text() assert "extend_test_003" in index_html diff --git a/tests/test_needs_builder.py b/tests/test_needs_builder.py index 4e3e34f01..7f64d1412 100644 --- a/tests/test_needs_builder.py +++ b/tests/test_needs_builder.py @@ -2,24 +2,16 @@ from pathlib import Path import pytest +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "needs", "srcdir": "doc_test/doc_needs_builder"}], indirect=True) -def test_doc_needs_builder(test_app): +def test_doc_needs_builder(test_app, snapshot): app = test_app app.build() - needs_json = Path(app.outdir, "needs.json") - with open(needs_json) as needs_file: - needs_file_content = needs_file.read() - - needs_list = json.loads(needs_file_content) - assert needs_list["versions"]["1.0"] - assert needs_list["versions"]["1.0"]["needs"]["TC_NEG_001"] - - # needs builder added new version needs from needs_files - assert needs_list["versions"]["2.0"] - assert needs_list["versions"]["2.0"]["needs"]["TEST_01"] + needs_list = json.loads(Path(app.outdir, "needs.json").read_text()) + assert needs_list == snapshot(exclude=props("created")) @pytest.mark.parametrize( diff --git a/tests/test_needs_id_builder.py b/tests/test_needs_id_builder.py new file mode 100644 index 000000000..cbf86ad46 --- /dev/null +++ b/tests/test_needs_id_builder.py @@ -0,0 +1,33 @@ +import json +import os +from pathlib import Path + +import pytest + +from sphinx_needs.config import NeedsSphinxConfig +from sphinx_needs.data import SphinxNeedsData + + +@pytest.mark.parametrize( + "test_app", [{"buildername": "needs_id", "srcdir": "doc_test/doc_needs_builder"}], indirect=True +) +def test_doc_needs_id_builder(test_app): + app = test_app + app.build() + out_dir = app.outdir + env = app.env + data = SphinxNeedsData(env) + needs_config = NeedsSphinxConfig(env.config) + needs = data.get_or_create_needs().values() # We need a list of needs for later filter checks + needs_build_json_per_id_path = needs_config.build_json_per_id_path + needs_id_path = os.path.join(out_dir, needs_build_json_per_id_path) + assert os.path.exists(needs_id_path) + for need in needs: + need_id = need["id"] + need_file_name = f"{need_id}.json" + needs_json = Path(needs_id_path, need_file_name) + assert os.path.exists(needs_json) + with open(needs_json) as needs_file: + needs_file_content = needs_file.read() + needs_list = json.loads(needs_file_content) + assert needs_list["versions"]["1.0"]["needs"][need_id]["docname"] diff --git a/tests/test_needs_warning.py b/tests/test_needs_warning.py index 07823ae4f..3a4f03411 100644 --- a/tests/test_needs_warning.py +++ b/tests/test_needs_warning.py @@ -13,7 +13,7 @@ def test_needs_warnings(test_app): warnings = warning.getvalue() # check multiple warning registration - assert 'invalid_status for "warnings" is already registered.' in warnings + assert "'invalid_status' in 'needs_warnings' is already registered." in warnings # check warnings contents assert "WARNING: invalid_status: failed" in warnings diff --git a/tests/test_needuml.py b/tests/test_needuml.py index d3df4bd17..45a0f518b 100644 --- a/tests/test_needuml.py +++ b/tests/test_needuml.py @@ -1,81 +1,28 @@ +import subprocess from pathlib import Path import pytest +from syrupy.filters import props @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml"}], indirect=True) -def test_doc_build_html(test_app): +def test_doc_build_html(test_app, snapshot): app = test_app app.build() - html = Path(app.outdir, "index.html").read_text(encoding="utf8") - assert html + assert Path(app.outdir, "index.html").read_text(encoding="utf8") -@pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml"}], indirect=True) -def test_needuml_option_key(test_app): - app = test_app - app.build() - - # check multiple needumls inside a need all_needs = app.env.needs_all_needs - all_needumls = app.env.needs_all_needumls - - assert len(all_needumls) == 9 - - # check first need with 2 needumls, 1 with key option, 1 without - curr_need_01 = all_needs["INT_002"] - assert curr_need_01 - - curr_need_uml_01 = all_needumls["needuml-index-1"] - curr_need_uml_02 = all_needumls["needuml-index-2"] - - assert curr_need_uml_01["key"] is None - assert curr_need_uml_02["key"] == "sequence" - - assert "class \"{{needs['ST_001'].title}}\" as test" in curr_need_uml_01["content"] - assert curr_need_uml_02["content"] == "Alice -> Bob: Hi Bob\nBob --> Alice: Hi Alice" - - assert curr_need_01["arch"]["diagram"] == curr_need_uml_01["content"] - assert curr_need_01["arch"]["sequence"] == curr_need_uml_02["content"] - - # check second need with 2 needumls, both have key option - curr_need_02 = all_needs["INT_003"] - curr_need_uml_03 = all_needumls["needuml-index-3"] - curr_need_uml_04 = all_needumls["needuml-index-4"] - - assert curr_need_uml_03["key"] == "class" - assert curr_need_uml_04["key"] == "sequence" + assert all_needs == snapshot(exclude=props("content_node")) - assert "class \"{{needs['ST_001'].title}}\" as test" in curr_need_uml_03["content"] - assert curr_need_uml_04["content"] == "Alice -> Bob: Hi Bob\nBob --> Alice: Hi Alice" - - assert "diagram" not in curr_need_02["arch"] - assert curr_need_02["arch"]["class"] == curr_need_uml_03["content"] - assert curr_need_02["arch"]["sequence"] == curr_need_uml_04["content"] - - # check third need with 4 needumls, 2 have key option, 2 don't have - curr_need_03 = all_needs["INT_004"] - curr_need_uml_05 = all_needumls["needuml-index-5"] - curr_need_uml_06 = all_needumls["needuml-index-6"] - curr_need_uml_07 = all_needumls["needuml-index-7"] - curr_need_uml_08 = all_needumls["needuml-index-8"] - - assert curr_need_uml_05["key"] == "class" - assert curr_need_uml_06["key"] is None - assert curr_need_uml_07["key"] == "sequence" - assert curr_need_uml_08["key"] is None - - # only store the first needuml from those don't have key option under diagram - assert curr_need_uml_06["content"] == "Superman -> Batman: Hi Bruce\nBatman --> Superman: Hi Clark" - assert curr_need_03["arch"]["diagram"] == curr_need_uml_06["content"] + all_needumls = app.env.needs_all_needumls + assert all_needumls == snapshot @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_duplicate_key"}], indirect=True ) def test_needuml_option_key_duplicate(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -94,8 +41,6 @@ def test_needuml_option_key_duplicate(test_app): "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_key_name_diagram"}], indirect=True ) def test_needuml_option_key_forbidden(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -110,29 +55,10 @@ def test_needuml_option_key_forbidden(test_app): ) -@pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml"}], indirect=True) -def test_needuml_jinja_uml_key(test_app): - app = test_app - app.build() - - # check multiple needumls inside a need - all_needs = app.env.needs_all_needs - all_needumls = app.env.needs_all_needumls - - curr_need = all_needs["INT_003"] - curr_needuml = all_needumls["needuml-index-3"] - assert curr_need["content_node"].children[1].rawsource == "needuml-index-3" - - assert curr_needuml["key"] == "class" - assert '{{uml("INT_002", "sequence")}}' in curr_needuml["content"] - - @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_diagram_allowmixing"}], indirect=True ) def test_needuml_diagram_allowmixing(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -143,7 +69,7 @@ def test_needuml_diagram_allowmixing(test_app): @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_save"}], indirect=True) -def test_needuml_save(test_app): +def test_needuml_save(test_app, snapshot): app = test_app app.build() @@ -155,46 +81,19 @@ def test_needuml_save(test_app): else: assert "doc_needuml_save/_build/html" in str(app.outdir) assert app.config.needs_build_needumls == "my_needumls" - saved_uml_path_01 = Path(app.outdir) / app.config.needs_build_needumls / "_build/my_needuml.puml" - assert saved_uml_path_01.exists() - - with open(saved_uml_path_01) as f1: - f1_contents = f1.readlines() - assert len(f1_contents) == 5 - assert f1_contents[0] == "@startuml\n" - assert f1_contents[1] == "\n" - assert f1_contents[2] == "DC -> Marvel: Hi Kevin\n" - assert f1_contents[3] == "Marvel --> DC: Anyone there?\n" - assert f1_contents[4] == "@enduml\n" - - saved_uml_path_02 = Path(app.outdir) / app.config.needs_build_needumls / "_out/sub_folder/my_needs.puml" - assert saved_uml_path_02.exists() - - with open(saved_uml_path_02) as f2: - f2_contents = f2.readlines() - assert len(f2_contents) == 5 - - assert f2_contents[0] == "@startuml\n" - assert f2_contents[1] == "\n" - - assert "User Story" in f2_contents[2] - assert "Test story" in f2_contents[2] - assert "ST_001" in f2_contents[2] - - assert "User Story" in f2_contents[3] - assert "Test story 2" in f2_contents[3] - assert "ST_002" in f2_contents[3] - - assert f2_contents[4] == "@enduml\n" + uml_path = Path(app.outdir).joinpath(app.config.needs_build_needumls) + umls = { + "uml1": uml_path.joinpath("_build", "my_needuml.puml").read_text(), + "uml2": uml_path.joinpath("_out", "sub_folder", "my_needs.puml").read_text(), + } + assert umls == snapshot @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_save_with_abs_path"}], indirect=True ) def test_needuml_save_with_abs_path(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -212,7 +111,7 @@ def test_needuml_save_with_abs_path(test_app): @pytest.mark.parametrize( "test_app", [{"buildername": "needumls", "srcdir": "doc_test/doc_needuml_save"}], indirect=True ) -def test_needumls_builder(test_app): +def test_needumls_builder(test_app, snapshot): app = test_app app.build() @@ -223,58 +122,26 @@ def test_needumls_builder(test_app): assert "doc_needuml_save\\_build\\needumls" in str(app.outdir) else: assert "doc_needuml_save/_build/needumls" in str(app.outdir) - saved_uml_path_01 = Path(app.outdir) / "_build/my_needuml.puml" - assert saved_uml_path_01.exists() - - with open(saved_uml_path_01) as f1: - f1_contents = f1.readlines() - assert len(f1_contents) == 5 - assert f1_contents[0] == "@startuml\n" - assert f1_contents[1] == "\n" - assert f1_contents[2] == "DC -> Marvel: Hi Kevin\n" - assert f1_contents[3] == "Marvel --> DC: Anyone there?\n" - assert f1_contents[4] == "@enduml\n" - - saved_uml_path_02 = Path(app.outdir) / "_out/sub_folder/my_needs.puml" - assert saved_uml_path_02.exists() - with open(saved_uml_path_02) as f2: - f2_contents = f2.readlines() - - assert len(f2_contents) == 5 - - assert f2_contents[0] == "@startuml\n" - assert f2_contents[1] == "\n" - - assert "User Story" in f2_contents[2] - assert "Test story" in f2_contents[2] - assert "ST_001" in f2_contents[2] - - assert "User Story" in f2_contents[3] - assert "Test story 2" in f2_contents[3] - assert "ST_002" in f2_contents[3] - - assert f2_contents[4] == "@enduml\n" + uml_path = Path(app.outdir) + umls = { + "uml1": uml_path.joinpath("_build", "my_needuml.puml").read_text(), + "uml2": uml_path.joinpath("_out", "sub_folder", "my_needs.puml").read_text(), + } + assert umls == snapshot @pytest.mark.parametrize("test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_filter"}], indirect=True) -def test_needuml_filter(test_app): +def test_needuml_filter(test_app, snapshot): app = test_app app.build() all_needumls = app.env.needs_all_needumls - assert len(all_needumls) == 1 - - needuml_01_content = all_needumls["needuml-index-0"]["content"] - assert "DC -> Marvel: Hi Kevin\n" in needuml_01_content - assert "Marvel --> DC: Anyone there?\n\n" in needuml_01_content - assert "{% for need in filter(\"type == 'story' and status != 'open'\") %}" in needuml_01_content + assert all_needumls == snapshot html = Path(app.outdir, "index.html").read_text(encoding="utf8") assert "as ST_002 [[../index.html#ST_002]]" in html - import subprocess - srcdir = Path(app.srcdir) out_dir = srcdir / "_build" @@ -285,20 +152,16 @@ def test_needuml_filter(test_app): @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_jinja_func_flow"}], indirect=True ) -def test_needuml_jinja_func_flow(test_app): +def test_needuml_jinja_func_flow(test_app, snapshot): app = test_app app.build() all_needumls = app.env.needs_all_needumls - assert len(all_needumls) == 1 - - assert '{{flow("ST_001")}}' in all_needumls["needuml-index-0"]["content"] + assert all_needumls == snapshot html = Path(app.outdir, "index.html").read_text(encoding="utf8") assert "as ST_001 [[../index.html#ST_001]]" in html - import subprocess - srcdir = Path(app.srcdir) out_dir = srcdir / "_build" @@ -310,8 +173,6 @@ def test_needuml_jinja_func_flow(test_app): "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_jinja_func_need_removed"}], indirect=True ) def test_needuml_jinja_func_need_removed(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -331,8 +192,6 @@ def test_needuml_jinja_func_need_removed(test_app): indirect=True, ) def test_doc_needarch_jinja_import_negative(test_app): - import subprocess - app = test_app srcdir = Path(app.srcdir) @@ -350,22 +209,17 @@ def test_doc_needarch_jinja_import_negative(test_app): @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needuml_jinja_func_ref"}], indirect=True ) -def test_needuml_jinja_func_ref(test_app): +def test_needuml_jinja_func_ref(test_app, snapshot): app = test_app app.build() all_needumls = app.env.needs_all_needumls - assert len(all_needumls) == 1 - - assert '{{ref("ST_001", option="title")}}' in all_needumls["needuml-index-0"]["content"] - assert '{{ref("ST_002", text="Different text to explain the story")}}' in all_needumls["needuml-index-0"]["content"] + assert all_needumls == snapshot html = Path(app.outdir, "index.html").read_text(encoding="utf8") assert "Marvel: [[../index.html#ST_001 Test story]]" in html assert "DC: [[../index.html#ST_002 Different text to explain the story]]" in html - import subprocess - srcdir = Path(app.srcdir) out_dir = srcdir / "_build"