diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 8b7c0b010..443019043 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -5,7 +5,7 @@ jobs: name: "py${{ matrix.python-version }} sp${{ matrix.sphinx-version }} do${{ matrix.docutils-version }} ${{ matrix.os }}" runs-on: ${{ matrix.os }} strategy: - fail-fast: true # Set on "false" to get the results of ALL builds + fail-fast: false # Set on "false" to get the results of ALL builds matrix: os: ["ubuntu-latest"] # 3.9.8 seems to be broken with type_ast @@ -56,3 +56,17 @@ jobs: with: python-version: '3.8' - uses: pre-commit/action@v3.0.0 + + check: + # This job does nothing and is only used for the branch protection + # see https://github.com/marketplace/actions/alls-green#why + if: always() + needs: + - lint + - tests + runs-on: ubuntu-latest + steps: + - name: Decide whether the needed jobs succeeded or failed + uses: re-actors/alls-green@release/v1 + with: + jobs: ${{ toJSON(needs) }} diff --git a/.gitignore b/.gitignore index 76e8f917d..768e4ca3d 100644 --- a/.gitignore +++ b/.gitignore @@ -30,7 +30,8 @@ docs/_images/need_bar_*.* .dockerignore .benchmarks/ - +tests/cypress/ +cypress/ need_bar_*.png need_pie_*.png diff --git a/AUTHORS b/AUTHORS index 821726ea2..b37fbbb7c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -37,3 +37,5 @@ Duodu Randy Christian Wappler Chris Sewell + +Simon Leiner diff --git a/Makefile b/Makefile index 554dddd4c..d29c5e689 100644 --- a/Makefile +++ b/Makefile @@ -10,11 +10,15 @@ lint: .PHONY: test test: - poetry run pytest -n auto --tb=long --ignore=tests/benchmarks tests/ + poetry run pytest -n auto -m "not jstest" --tb=long --ignore=tests/benchmarks tests/ .PHONY: test test-short: - poetry run pytest -n auto --tb=long --ignore-glob="*official*" --ignore=tests/benchmarks tests/ + poetry run pytest -n auto -m "not jstest" --tb=long --ignore-glob="*official*" --ignore=tests/benchmarks tests/ + +.PHONY: test +test-js: + poetry run pytest -n 1 -m "jstest" --tb=long --ignore-glob="*official*" --ignore=tests/benchmarks tests/ .PHONY: benchmark-time benchmark-time: diff --git a/docs/contributing.rst b/docs/contributing.rst index 7a06e5a22..715c49830 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -121,6 +121,103 @@ These snapshots can be updated by running: pip install -r docs/requirements.txt +Running JS Testcases with PyTest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +**Setup Cypress Locally** + +* Install Node JS on your computer and ensure it can be accessed through the CMD. +* Install Cypress using the npm package manager by running ``npm install cypress``. Visit this link for more information on `how to install Cypress `_. +* Verify if Cypress is installed correctly and is executable by running: ``npx cypress verify``. Get out this page for more information about `Cypress commandline `_. +* If everything is successful then we can use Cypress. + +**Enable Cypress Test in Python Test Files** + +Under the ``js_test`` folder, you can save your Cypress JS test files (files should end with: ``*.cy.js``). For each Cypress JS test file, you will need to write the Cypress JS test cases in the file. You can read more from the `Cypress Docs `_. You can also check the ``tests/js_test/sn-collapse-button.cy.js`` file as reference. + +In your Python test files, you must mark every JS related test case with the marker - ``jstest`` and you must include the ``spec_pattern`` key-value pair as part of the ``test_app`` fixture parameter. +Also, you need to pass the ``test_server`` fixture to your test function for it to use the automated HTTP test server. For example, your test case could look like this: + +.. code-block:: python + + # tests/test_sn_collapse_button.py + + import pytest + + + @pytest.mark.jstest + @pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/variant_doc", + "tags": ["tag_a"], + "spec_pattern": "js_test/js-test-sn-collapse-button.cy.js" + } + ], + indirect=True, + ) + def test_collapse_button_in_docs(test_app, test_server): + ... + +.. note:: + + The ``spec_pattern`` key is required to ensure Cypress locates your test files or folder. Visit this link for more info on how to set the `spec_pattern `_. + +After you set the ``spec_pattern`` key-value pair as part of the ``test_app`` fixture parameter, you can call ``app.test_js()`` in your Python test case to run a JS test for the ``spec_pattern`` you provided. For example, you can use ``app.test_js()`` like below: + +.. code-block:: python + + # tests/test_sn_collapse_button.py + + import pytest + + + @pytest.mark.jstest + @pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/variant_doc", + "tags": ["tag_a"], + "spec_pattern": "js_test/js-test-sn-collapse-button.cy.js" + } + ], + indirect=True, + ) + def test_collapse_button_in_docs(test_app, test_server): + """Check if the Sphinx-Needs collapse button works in the provided documentation source.""" + app = test_app + app.build() + + # Call `app.test_js()` to run the JS test for a particular specPattern + js_test_result = app.test_js() + + # Check the return code and stdout + assert js_test_result["returncode"] == 0 + assert "All specs passed!" in js_test_result["stdout"].decode("utf-8") + +.. note:: + + ``app.test_js()`` will return a dictionary object containing the ``returncode``, ``stdout``, and ``stderr``. Example: + + .. code-block:: python + + return { + "returncode": 0, + "stdout": "Test passed string", + "stderr": "Errors encountered, + } + +You can run the ``make test-js`` command to check all JS testcases. + +.. note:: + + The ``http_server`` process invoked by the ``make test-js`` command may not terminate properly in some instances. + Kindly check your system's monitoring app to end the process if not terminated automatically. + Linting & Formatting -------------------- diff --git a/noxfile.py b/noxfile.py index e9b3ffddf..dd2c0cf54 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,6 +14,7 @@ TEST_DEPENDENCIES = [ "pytest", "pytest-xdist", + "pytest-xprocess", "syrupy", "responses", "lxml", diff --git a/poetry.lock b/poetry.lock index af90bc526..84a8dc9ea 100644 --- a/poetry.lock +++ b/poetry.lock @@ -34,17 +34,21 @@ tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pyte [[package]] name = "babel" -version = "2.12.1" +version = "2.13.1" description = "Internationalization utilities" optional = false python-versions = ">=3.7" files = [ - {file = "Babel-2.12.1-py3-none-any.whl", hash = "sha256:b4246fb7677d3b98f501a39d43396d3cafdc8eadb045f4a31be01863f655c610"}, - {file = "Babel-2.12.1.tar.gz", hash = "sha256:cc2d99999cd01d44420ae725a21c9e3711b3aadc7976d6147f622d8581963455"}, + {file = "Babel-2.13.1-py3-none-any.whl", hash = "sha256:7077a4984b02b6727ac10f1f7294484f737443d7e2e66c5e4380e41a3ae0b4ed"}, + {file = "Babel-2.13.1.tar.gz", hash = "sha256:33e0952d7dd6374af8dbf6768cc4ddf3ccfefc244f9986d4074704f2fbd18900"}, ] [package.dependencies] pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} +setuptools = {version = "*", markers = "python_version >= \"3.12\""} + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "black" @@ -106,86 +110,101 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.3.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7.0" files = [ - {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"}, + {file = "charset-normalizer-3.3.1.tar.gz", hash = "sha256:d9137a876020661972ca6eec0766d81aef8a5627df628b664b234b73396e727e"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8aee051c89e13565c6bd366813c386939f8e928af93c29fda4af86d25b73d8f8"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:352a88c3df0d1fa886562384b86f9a9e27563d4704ee0e9d56ec6fcd270ea690"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:223b4d54561c01048f657fa6ce41461d5ad8ff128b9678cfe8b2ecd951e3f8a2"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f861d94c2a450b974b86093c6c027888627b8082f1299dfd5a4bae8e2292821"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1171ef1fc5ab4693c5d151ae0fdad7f7349920eabbaca6271f95969fa0756c2d"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28f512b9a33235545fbbdac6a330a510b63be278a50071a336afc1b78781b147"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0e842112fe3f1a4ffcf64b06dc4c61a88441c2f02f373367f7b4c1aa9be2ad5"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3f9bc2ce123637a60ebe819f9fccc614da1bcc05798bbbaf2dd4ec91f3e08846"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f194cce575e59ffe442c10a360182a986535fd90b57f7debfaa5c845c409ecc3"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:9a74041ba0bfa9bc9b9bb2cd3238a6ab3b7618e759b41bd15b5f6ad958d17605"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:b578cbe580e3b41ad17b1c428f382c814b32a6ce90f2d8e39e2e635d49e498d1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6db3cfb9b4fcecb4390db154e75b49578c87a3b9979b40cdf90d7e4b945656e1"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:debb633f3f7856f95ad957d9b9c781f8e2c6303ef21724ec94bea2ce2fcbd056"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win32.whl", hash = "sha256:87071618d3d8ec8b186d53cb6e66955ef2a0e4fa63ccd3709c0c90ac5a43520f"}, + {file = "charset_normalizer-3.3.1-cp310-cp310-win_amd64.whl", hash = "sha256:e372d7dfd154009142631de2d316adad3cc1c36c32a38b16a4751ba78da2a397"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ae4070f741f8d809075ef697877fd350ecf0b7c5837ed68738607ee0a2c572cf"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:58e875eb7016fd014c0eea46c6fa92b87b62c0cb31b9feae25cbbe62c919f54d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dbd95e300367aa0827496fe75a1766d198d34385a58f97683fe6e07f89ca3e3c"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de0b4caa1c8a21394e8ce971997614a17648f94e1cd0640fbd6b4d14cab13a72"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:985c7965f62f6f32bf432e2681173db41336a9c2611693247069288bcb0c7f8b"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a15c1fe6d26e83fd2e5972425a772cca158eae58b05d4a25a4e474c221053e2d"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ae55d592b02c4349525b6ed8f74c692509e5adffa842e582c0f861751701a673"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:be4d9c2770044a59715eb57c1144dedea7c5d5ae80c68fb9959515037cde2008"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:851cf693fb3aaef71031237cd68699dded198657ec1e76a76eb8be58c03a5d1f"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:31bbaba7218904d2eabecf4feec0d07469284e952a27400f23b6628439439fa7"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:871d045d6ccc181fd863a3cd66ee8e395523ebfbc57f85f91f035f50cee8e3d4"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:501adc5eb6cd5f40a6f77fbd90e5ab915c8fd6e8c614af2db5561e16c600d6f3"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f5fb672c396d826ca16a022ac04c9dce74e00a1c344f6ad1a0fdc1ba1f332213"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win32.whl", hash = "sha256:bb06098d019766ca16fc915ecaa455c1f1cd594204e7f840cd6258237b5079a8"}, + {file = "charset_normalizer-3.3.1-cp311-cp311-win_amd64.whl", hash = "sha256:8af5a8917b8af42295e86b64903156b4f110a30dca5f3b5aedea123fbd638bff"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:7ae8e5142dcc7a49168f4055255dbcced01dc1714a90a21f87448dc8d90617d1"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5b70bab78accbc672f50e878a5b73ca692f45f5b5e25c8066d748c09405e6a55"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ceca5876032362ae73b83347be8b5dbd2d1faf3358deb38c9c88776779b2e2f"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34d95638ff3613849f473afc33f65c401a89f3b9528d0d213c7037c398a51296"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9edbe6a5bf8b56a4a84533ba2b2f489d0046e755c29616ef8830f9e7d9cf5728"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6a02a3c7950cafaadcd46a226ad9e12fc9744652cc69f9e5534f98b47f3bbcf"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10b8dd31e10f32410751b3430996f9807fc4d1587ca69772e2aa940a82ab571a"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edc0202099ea1d82844316604e17d2b175044f9bcb6b398aab781eba957224bd"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b891a2f68e09c5ef989007fac11476ed33c5c9994449a4e2c3386529d703dc8b"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:71ef3b9be10070360f289aea4838c784f8b851be3ba58cf796262b57775c2f14"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:55602981b2dbf8184c098bc10287e8c245e351cd4fdcad050bd7199d5a8bf514"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:46fb9970aa5eeca547d7aa0de5d4b124a288b42eaefac677bde805013c95725c"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:520b7a142d2524f999447b3a0cf95115df81c4f33003c51a6ab637cbda9d0bf4"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win32.whl", hash = "sha256:8ec8ef42c6cd5856a7613dcd1eaf21e5573b2185263d87d27c8edcae33b62a61"}, + {file = "charset_normalizer-3.3.1-cp312-cp312-win_amd64.whl", hash = "sha256:baec8148d6b8bd5cee1ae138ba658c71f5b03e0d69d5907703e3e1df96db5e41"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:63a6f59e2d01310f754c270e4a257426fe5a591dc487f1983b3bbe793cf6bac6"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d6bfc32a68bc0933819cfdfe45f9abc3cae3877e1d90aac7259d57e6e0f85b1"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f3100d86dcd03c03f7e9c3fdb23d92e32abbca07e7c13ebd7ddfbcb06f5991f"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39b70a6f88eebe239fa775190796d55a33cfb6d36b9ffdd37843f7c4c1b5dc67"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e12f8ee80aa35e746230a2af83e81bd6b52daa92a8afaef4fea4a2ce9b9f4fa"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b6cefa579e1237ce198619b76eaa148b71894fb0d6bcf9024460f9bf30fd228"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:61f1e3fb621f5420523abb71f5771a204b33c21d31e7d9d86881b2cffe92c47c"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:4f6e2a839f83a6a76854d12dbebde50e4b1afa63e27761549d006fa53e9aa80e"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:1ec937546cad86d0dce5396748bf392bb7b62a9eeb8c66efac60e947697f0e58"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:82ca51ff0fc5b641a2d4e1cc8c5ff108699b7a56d7f3ad6f6da9dbb6f0145b48"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:633968254f8d421e70f91c6ebe71ed0ab140220469cf87a9857e21c16687c034"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win32.whl", hash = "sha256:c0c72d34e7de5604df0fde3644cc079feee5e55464967d10b24b1de268deceb9"}, + {file = "charset_normalizer-3.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:63accd11149c0f9a99e3bc095bbdb5a464862d77a7e309ad5938fbc8721235ae"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5a3580a4fdc4ac05f9e53c57f965e3594b2f99796231380adb2baaab96e22761"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2465aa50c9299d615d757c1c888bc6fef384b7c4aec81c05a0172b4400f98557"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cb7cd68814308aade9d0c93c5bd2ade9f9441666f8ba5aa9c2d4b389cb5e2a45"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91e43805ccafa0a91831f9cd5443aa34528c0c3f2cc48c4cb3d9a7721053874b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:854cc74367180beb327ab9d00f964f6d91da06450b0855cbbb09187bcdb02de5"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c15070ebf11b8b7fd1bfff7217e9324963c82dbdf6182ff7050519e350e7ad9f"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c4c99f98fc3a1835af8179dcc9013f93594d0670e2fa80c83aa36346ee763d2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3fb765362688821404ad6cf86772fc54993ec11577cd5a92ac44b4c2ba52155b"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dced27917823df984fe0c80a5c4ad75cf58df0fbfae890bc08004cd3888922a2"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a66bcdf19c1a523e41b8e9d53d0cedbfbac2e93c649a2e9502cb26c014d0980c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:ecd26be9f112c4f96718290c10f4caea6cc798459a3a76636b817a0ed7874e42"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:3f70fd716855cd3b855316b226a1ac8bdb3caf4f7ea96edcccc6f484217c9597"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:17a866d61259c7de1bdadef418a37755050ddb4b922df8b356503234fff7932c"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win32.whl", hash = "sha256:548eefad783ed787b38cb6f9a574bd8664468cc76d1538215d510a3cd41406cb"}, + {file = "charset_normalizer-3.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:45f053a0ece92c734d874861ffe6e3cc92150e32136dd59ab1fb070575189c97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bc791ec3fd0c4309a753f95bb6c749ef0d8ea3aea91f07ee1cf06b7b02118f2f"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0c8c61fb505c7dad1d251c284e712d4e0372cef3b067f7ddf82a7fa82e1e9a93"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2c092be3885a1b7899cd85ce24acedc1034199d6fca1483fa2c3a35c86e43041"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2000c54c395d9e5e44c99dc7c20a64dc371f777faf8bae4919ad3e99ce5253e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4cb50a0335382aac15c31b61d8531bc9bb657cfd848b1d7158009472189f3d62"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c30187840d36d0ba2893bc3271a36a517a717f9fd383a98e2697ee890a37c273"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe81b35c33772e56f4b6cf62cf4aedc1762ef7162a31e6ac7fe5e40d0149eb67"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d0bf89afcbcf4d1bb2652f6580e5e55a840fdf87384f6063c4a4f0c95e378656"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:06cf46bdff72f58645434d467bf5228080801298fbba19fe268a01b4534467f5"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:3c66df3f41abee950d6638adc7eac4730a306b022570f71dd0bd6ba53503ab57"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:cd805513198304026bd379d1d516afbf6c3c13f4382134a2c526b8b854da1c2e"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:9505dc359edb6a330efcd2be825fdb73ee3e628d9010597aa1aee5aa63442e97"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:31445f38053476a0c4e6d12b047b08ced81e2c7c712e5a1ad97bc913256f91b2"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win32.whl", hash = "sha256:bd28b31730f0e982ace8663d108e01199098432a30a4c410d06fe08fdb9e93f4"}, + {file = "charset_normalizer-3.3.1-cp39-cp39-win_amd64.whl", hash = "sha256:555fe186da0068d3354cdf4bbcbc609b0ecae4d04c921cc13e209eece7720727"}, + {file = "charset_normalizer-3.3.1-py3-none-any.whl", hash = "sha256:800561453acdecedaac137bf09cd719c7a440b6800ec182f077bb8e7025fb708"}, ] [[package]] @@ -855,40 +874,46 @@ files = [ [[package]] name = "memray" -version = "1.9.1" +version = "1.10.0" description = "A memory profiler for Python applications" optional = false python-versions = ">=3.7.0" files = [ - {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"}, + {file = "memray-1.10.0-cp310-cp310-macosx_10_14_x86_64.whl", hash = "sha256:843a688877691746f9d1835cfa8a65139948471bdd78720435808d20bc30a1cc"}, + {file = "memray-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6937d7ef67d18ccc01c3250cdf3b4ef1445b859ee8756f09e3d11bd3ff0c7d67"}, + {file = "memray-1.10.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:23e8c402625cfb32d0e9edb5ec0945f3e5e54bc6b0c5699f6284302082b80bd4"}, + {file = "memray-1.10.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f16c5c8730b616613dc8bafe32649ca6bd7252606251eb00148582011758d0b5"}, + {file = "memray-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7aeb47174c42e99740a8e2b3b6fe0932c95d987258d48a746974ead19176c26"}, + {file = "memray-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2ce59ef485db3634de98b3a026d2450fc0a875e3a58a9ea85f7a89098841defe"}, + {file = "memray-1.10.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:53a8f66af18b1f3bcf5c9f3c95ae4134dd675903a38f9d0e6341b7bca01b63d0"}, + {file = "memray-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9627184c926252c8f719c301f1fefe970f0d033c643a6448b93fed2889d1ea94"}, + {file = "memray-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c3a14960838d89a91747885897d34134afb65883cc3b0ed7ff30fe1af00f9fe6"}, + {file = "memray-1.10.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:22f2a47871c172a0539bd72737bb6b294fc10c510464066b825d90fcd3bb4916"}, + {file = "memray-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c401c57f49c4c5f1fecaee1e746f537cdc6680da05fb963dc143bd08ee109bf"}, + {file = "memray-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ce22a887a585ef5020896de89ffc793e531b65ccc81fbafcc7886010c2c562b3"}, + {file = "memray-1.10.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:b75040f28e8678d0e9c4907d55c95cf26db8ef5adc9941a228f1b280a9efd9c0"}, + {file = "memray-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:95e563d9c976e429ad597ad2720d95cebbe8bac891a3082465439143e2740772"}, + {file = "memray-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:663d463e89a64bae4a6b2f8c837d11a3d094834442d536a4165e1d31899a3500"}, + {file = "memray-1.10.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a21745fb516b7a6efcd40aa7487c59e9313fcfc782d0193fcfcf00b48426874"}, + {file = "memray-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf6d683c4f8d25c6ad06ae18715f218983c5eb86803953615e902d632fdf6ec1"}, + {file = "memray-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b311e91203be71e1a0ce5e4f978137765bcb1045f3bf5646129c83c5b96ab3c"}, + {file = "memray-1.10.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:68bd8df023c8a32f44c11d997e5c536837e27c0955daf557d3a377edd55a1dd3"}, + {file = "memray-1.10.0-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:322ed0b69014a0969b777768d461a785203f81f9864386b666b5b26645d9c294"}, + {file = "memray-1.10.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a9e985fb7646b0475c303919d19211d2aa54e5a9e2cd2a102472299be5dbebd3"}, + {file = "memray-1.10.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4eba29179772b4a2e440a065b320b03bc2e73fe2648bdf7936aa3b9a086fab4a"}, + {file = "memray-1.10.0-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:b681519357d94f5f0857fbc6029e7c44d3f41436109e955a14fd312d8317bc35"}, + {file = "memray-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8196c684f1be8fe423e5cdd2356d4255a2cb482a1f3e89612b70d2a2862cf5bb"}, + {file = "memray-1.10.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:898acd60f57a10dc5aaf1fd64aa2f821f0420114f3f60c3058083788603f173a"}, + {file = "memray-1.10.0-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6fd13ef666c7fced9768d1cfabf71dc6dfa6724935a8dff463495ac2dc5e13a4"}, + {file = "memray-1.10.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e356af93e3b031c83957e9ac1a653f5aaba5df1e357dd17142f5ed19bb3dc660"}, + {file = "memray-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92c372cb262eddd23049f945ca9527f0e4cc7c40a070aade1802d066f680885b"}, + {file = "memray-1.10.0-cp39-cp39-macosx_10_14_x86_64.whl", hash = "sha256:38393c86ce6d0a08e6ec0eb1401d49803b7c0c950c2565386751cdc81568cba8"}, + {file = "memray-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a8bb7fbd8303c4f0017ba7faef6b88f904cda2931ed667cbf3b98f024b3bc44"}, + {file = "memray-1.10.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8d56f37a34125684746c13d24bd7a3fb17549b0bb355eb50969eb11e05e3ba62"}, + {file = "memray-1.10.0-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:85c32d6613d81b075f740e398c4d653e0803cd48e82c33dcd584c109d6782666"}, + {file = "memray-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:566602b2143e06b3d592901d98c52ce4599e71aa2555146eeb5cec03506f9498"}, + {file = "memray-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:391aac6c9f744528d3186bc82d708a1acc83525778f804045d7c96f860f8ec98"}, + {file = "memray-1.10.0.tar.gz", hash = "sha256:38322e052b882790993412f1840517a51818aa55c47037f69915b2007f2c4cee"}, ] [package.dependencies] @@ -1018,13 +1043,13 @@ files = [ [[package]] name = "packaging" -version = "23.1" +version = "23.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -1130,13 +1155,13 @@ files = [ [[package]] name = "platformdirs" -version = "3.10.0" +version = "3.11.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-3.11.0-py3-none-any.whl", hash = "sha256:e9d171d00af68be50e9202731309c4e658fd8bc76f55c11c7dd760d023bda68e"}, + {file = "platformdirs-3.11.0.tar.gz", hash = "sha256:cf8ee52a3afdb965072dcc652433e0c7e3e40cf5ea1477cd4b3b1d2eb75495b3"}, ] [package.dependencies] @@ -1183,6 +1208,45 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" +[[package]] +name = "psutil" +version = "5.9.6" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.6-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:fb8a697f11b0f5994550555fcfe3e69799e5b060c8ecf9e2f75c69302cc35c0d"}, + {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:91ecd2d9c00db9817a4b4192107cf6954addb5d9d67a969a4f436dbc9200f88c"}, + {file = "psutil-5.9.6-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:10e8c17b4f898d64b121149afb136c53ea8b68c7531155147867b7b1ac9e7e28"}, + {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:18cd22c5db486f33998f37e2bb054cc62fd06646995285e02a51b1e08da97017"}, + {file = "psutil-5.9.6-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:ca2780f5e038379e520281e4c032dddd086906ddff9ef0d1b9dcf00710e5071c"}, + {file = "psutil-5.9.6-cp27-none-win32.whl", hash = "sha256:70cb3beb98bc3fd5ac9ac617a327af7e7f826373ee64c80efd4eb2856e5051e9"}, + {file = "psutil-5.9.6-cp27-none-win_amd64.whl", hash = "sha256:51dc3d54607c73148f63732c727856f5febec1c7c336f8f41fcbd6315cce76ac"}, + {file = "psutil-5.9.6-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:c69596f9fc2f8acd574a12d5f8b7b1ba3765a641ea5d60fb4736bf3c08a8214a"}, + {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:92e0cc43c524834af53e9d3369245e6cc3b130e78e26100d1f63cdb0abeb3d3c"}, + {file = "psutil-5.9.6-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:748c9dd2583ed86347ed65d0035f45fa8c851e8d90354c122ab72319b5f366f4"}, + {file = "psutil-5.9.6-cp36-cp36m-win32.whl", hash = "sha256:3ebf2158c16cc69db777e3c7decb3c0f43a7af94a60d72e87b2823aebac3d602"}, + {file = "psutil-5.9.6-cp36-cp36m-win_amd64.whl", hash = "sha256:ff18b8d1a784b810df0b0fff3bcb50ab941c3b8e2c8de5726f9c71c601c611aa"}, + {file = "psutil-5.9.6-cp37-abi3-win32.whl", hash = "sha256:a6f01f03bf1843280f4ad16f4bde26b817847b4c1a0db59bf6419807bc5ce05c"}, + {file = "psutil-5.9.6-cp37-abi3-win_amd64.whl", hash = "sha256:6e5fb8dc711a514da83098bc5234264e551ad980cec5f85dabf4d38ed6f15e9a"}, + {file = "psutil-5.9.6-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:daecbcbd29b289aac14ece28eca6a3e60aa361754cf6da3dfb20d4d32b6c7f57"}, + {file = "psutil-5.9.6.tar.gz", hash = "sha256:e4b92ddcd7dd4cdd3f900180ea1e104932c7bce234fb88976e2a3b296441225a"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "py" +version = "1.11.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "py-1.11.0-py2.py3-none-any.whl", hash = "sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378"}, + {file = "py-1.11.0.tar.gz", hash = "sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719"}, +] + [[package]] name = "py-cpuinfo" version = "9.0.0" @@ -1260,13 +1324,13 @@ files = [ [[package]] name = "pytest" -version = "7.4.2" +version = "7.4.3" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, - {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, ] [package.dependencies] @@ -1321,6 +1385,22 @@ psutil = ["psutil (>=3.0)"] setproctitle = ["setproctitle"] testing = ["filelock"] +[[package]] +name = "pytest-xprocess" +version = "0.22.2" +description = "A pytest plugin for managing processes across test runs." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-xprocess-0.22.2.tar.gz", hash = "sha256:599ee25b938e8f259e18d9c5b4d6384884f8a6a28ca51eed32d0d9526bdcf77c"}, + {file = "pytest_xprocess-0.22.2-py3-none-any.whl", hash = "sha256:dabd65bc06485df85bb40d26d103d9ba9b94c63ce80a2358bf642bd679bcc742"}, +] + +[package.dependencies] +psutil = "*" +py = "*" +pytest = ">=2.8" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1473,13 +1553,13 @@ tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asy [[package]] name = "rich" -version = "13.5.2" +version = "13.6.0" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false python-versions = ">=3.7.0" files = [ - {file = "rich-13.5.2-py3-none-any.whl", hash = "sha256:146a90b3b6b47cac4a73c12866a499e9817426423f57c5a66949c086191a8808"}, - {file = "rich-13.5.2.tar.gz", hash = "sha256:fb9d6c0a0f643c99eed3875b5377a184132ba9be4d61516a55273d3554d75a39"}, + {file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, + {file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, ] [package.dependencies] @@ -1795,17 +1875,17 @@ files = [ [[package]] name = "types-requests" -version = "2.31.0.2" +version = "2.31.0.10" description = "Typing stubs for requests" optional = false -python-versions = "*" +python-versions = ">=3.7" files = [ - {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"}, + {file = "types-requests-2.31.0.10.tar.gz", hash = "sha256:dc5852a76f1eaf60eafa81a2e50aefa3d1f015c34cf0cba130930866b1b22a92"}, + {file = "types_requests-2.31.0.10-py3-none-any.whl", hash = "sha256:b32b9a86beffa876c0c3ac99a4cd3b8b51e973fb8e3bd4e0a6bb32c7efad80fc"}, ] [package.dependencies] -types-urllib3 = "*" +urllib3 = ">=2" [[package]] name = "types-setuptools" @@ -1832,17 +1912,6 @@ files = [ {file = "types_toml-0.10.8.7-py3-none-any.whl", hash = "sha256:61951da6ad410794c97bec035d59376ce1cbf4453dc9b6f90477e81e4442d631"}, ] -[[package]] -name = "types-urllib3" -version = "1.26.25.14" -description = "Typing stubs for urllib3" -optional = false -python-versions = "*" -files = [ - {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.7.1" @@ -1856,13 +1925,13 @@ files = [ [[package]] name = "urllib3" -version = "2.0.4" +version = "2.0.7" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.7" files = [ - {file = "urllib3-2.0.4-py3-none-any.whl", hash = "sha256:de7df1803967d2c2a98e4b11bb7d6bd9210474c46e8a0401514e3a42a75ebde4"}, - {file = "urllib3-2.0.4.tar.gz", hash = "sha256:8d22f86aae8ef5e410d4f539fde9ce6b2113a001bb4d189e0aed70642d602b11"}, + {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, + {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, ] [package.extras] @@ -1873,13 +1942,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.24.6" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.24.6-py3-none-any.whl", hash = "sha256:520d056652454c5098a00c0f073611ccbea4c79089331f60bf9d7ba247bb7381"}, + {file = "virtualenv-20.24.6.tar.gz", hash = "sha256:02ece4f56fbf939dbbc33c0715159951d6bf14aaf5457b092e4548e1382455af"}, ] [package.dependencies] @@ -1910,4 +1979,4 @@ testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more [metadata] lock-version = "2.0" python-versions = ">=3.7.0,<4.0" -content-hash = "74d9e2375488c28c1cd6286e8cf27985fa7fb5847f81f5c678a94a086dbaf626" +content-hash = "8f8189d6a246a3f306a15f36307f352384b5bcf92caa6435f7b617f82f47e325" diff --git a/pyproject.toml b/pyproject.toml index 449f8bb3e..f56cedca6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,6 +49,7 @@ pre-commit = "^2" lxml = "^4.6.5" pytest = "^7" pytest-xdist="*" # parallelisation +pytest-xprocess = "^0.22.2" syrupy = ">=3,<5" responses = "^0.22.0" requests-mock = ">=1.9.3" @@ -74,6 +75,9 @@ packaging = "*" [tool.pytest.ini_options] asyncio_mode= "auto" +markers = [ + "jstest: marks tests as JavaScript test (deselect with '-m \"not jstest\"')", +] [tool.black] line-length = 120 diff --git a/sphinx_needs/builder.py b/sphinx_needs/builder.py index 454cc95b9..5674d2323 100644 --- a/sphinx_needs/builder.py +++ b/sphinx_needs/builder.py @@ -1,5 +1,5 @@ import os -from typing import Iterable, List, Optional, Set +from typing import Iterable, List, Optional, Sequence, Set from docutils import nodes from sphinx import version_info @@ -8,28 +8,58 @@ from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import NeedsInfoType, SphinxNeedsData +from sphinx_needs.directives.need import post_process_needs_data from sphinx_needs.logging import get_logger from sphinx_needs.needsfile import NeedsList -log = get_logger(__name__) +LOGGER = get_logger(__name__) class NeedsBuilder(Builder): + """Output the needs data as a JSON file, + filtering by the ``needs_builder_filter`` config option if set, + and writing to ``needs.json`` (or the ``needs_file`` config option if set) + in the output folder. + + Note this builder normally completely skips the write phase, + where all documents are post-transformed, to improve performance. + It is assumed all need data is already read in the read phase, + and the post-processing of the data is done in the finish phase. + + However, if the ``export_id`` option is set for any directives, + the write phase is still run, since this filter data is currently only added there. + A warning is issued in this case. + """ + name = "needs" format = "needs" file_suffix = ".txt" links_suffix = None - def write_doc(self, docname: str, doctree: nodes.document) -> None: - pass + def get_outdated_docs(self) -> Iterable[str]: + return [] + + def write( + self, + build_docnames: Iterable[str], + updated_docnames: Sequence[str], + method: str = "update", + ) -> None: + if not SphinxNeedsData(self.env).has_export_filters: + return + LOGGER.warning( + "At least one use of `export_id` directive option, requires a slower build", type="needs", subtype="build" + ) + return super().write(build_docnames, updated_docnames, method) def finish(self) -> None: - env = self.env - data = SphinxNeedsData(env) + post_process_needs_data(self.app) + + data = SphinxNeedsData(self.env) + needs_config = NeedsSphinxConfig(self.env.config) filters = data.get_or_create_filters() - version = getattr(env.config, "version", "unset") - needs_list = NeedsList(env.config, self.outdir, self.srcdir) - needs_config = NeedsSphinxConfig(env.config) + version = getattr(self.env.config, "version", "unset") + needs_list = NeedsList(self.env.config, self.outdir, self.srcdir) if needs_config.file: needs_file = needs_config.file @@ -38,7 +68,7 @@ def finish(self) -> None: # check if needs.json file exists in conf.py directory needs_json = os.path.join(self.srcdir, "needs.json") if os.path.exists(needs_json): - log.info("needs.json found, but will not be used because needs_file not configured.") + LOGGER.info("needs.json found, but will not be used because needs_file not configured.") # Clean needs_list from already stored needs of the current version. # This is needed as needs could have been removed from documentation and if this is the case, @@ -62,25 +92,30 @@ def finish(self) -> None: try: needs_list.write_json() except Exception as e: - log.error(f"Error during writing json file: {e}") + LOGGER.error(f"Error during writing json file: {e}") else: - log.info("Needs successfully exported") + LOGGER.info("Needs successfully exported") - def get_outdated_docs(self) -> Iterable[str]: - return [] + def get_target_uri(self, _docname: str, _typ: Optional[str] = None) -> str: + # only needed if the write phase is run + return "" def prepare_writing(self, _docnames: Set[str]) -> None: + # only needed if the write phase is run + pass + + def write_doc(self, docname: str, doctree: nodes.document) -> None: + # only needed if the write phase is run pass def write_doc_serialized(self, _docname: str, _doctree: nodes.document) -> None: + # only needed if the write phase is run pass def cleanup(self) -> None: + # only needed if the write phase is run pass - def get_target_uri(self, _docname: str, _typ: Optional[str] = None) -> str: - return "" - def build_needs_json(app: Sphinx, _exception: Exception) -> None: env = app.env @@ -101,7 +136,87 @@ def build_needs_json(app: Sphinx, _exception: Exception) -> None: needs_builder.finish() +class NeedsIdBuilder(Builder): + """Output the needs data as multiple JSON files, one per need, + filtering by the ``needs_builder_filter`` config option if set, + and writing to the ``needs_id`` folder (or the ``build_json_per_id_path`` config option if set) + in the output folder. + + Note this builder completely skips the write phase, + where all documents are post-transformed, to improve performance. + It is assumed all need data is already read in the read phase, + and the post-processing of the data is done in the finish phase. + """ + + name = "needs_id" + format = "needs" + file_suffix = ".txt" + links_suffix = None + + def get_outdated_docs(self) -> Iterable[str]: + return [] + + def write( + self, + build_docnames: Iterable[str], + updated_docnames: Sequence[str], + method: str = "update", + ) -> None: + pass + + def finish(self) -> None: + post_process_needs_data(self.app) + + data = SphinxNeedsData(self.env) + needs = data.get_or_create_needs().values() # We need a list of needs for later filter checks + version = getattr(self.env.config, "version", "unset") + needs_config = NeedsSphinxConfig(self.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(self.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: + LOGGER.error(f"Needs-ID Builder {id} error: {e}") + LOGGER.info("Needs_id successfully exported") + + +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() + + class NeedumlsBuilder(Builder): + """Write generated PlantUML input files to the output dir, + that were generated by need directives, + if they have a ``save`` field set, + denoting the path relative to the output folder. + """ + name = "needumls" def write_doc(self, docname: str, doctree: nodes.document) -> None: @@ -120,7 +235,7 @@ def finish(self) -> None: if not os.path.exists(save_dir): os.makedirs(save_dir, exist_ok=True) - log.info(f"Storing needuml data to file {save_path}.") + LOGGER.info(f"Storing needuml data to file {save_path}.") with open(save_path, "w") as f: f.write(puml_content) @@ -161,74 +276,3 @@ 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/data.py b/sphinx_needs/data.py index 9fa8d44f2..182324ae2 100644 --- a/sphinx_needs/data.py +++ b/sphinx_needs/data.py @@ -25,9 +25,10 @@ class NeedsFilterType(TypedDict): status: list[str] tags: list[str] types: list[str] - export_id: str result: list[str] amount: int + export_id: str + """If set, the filter is exported with this ID in the needs.json file.""" class NeedsBaseDataType(TypedDict): @@ -271,6 +272,7 @@ class NeedsFilteredBaseType(NeedsBaseDataType): filter_code: list[str] filter_func: None | str export_id: str + """If set, the filter is exported with this ID in the needs.json file.""" class NeedsFilteredDiagramBaseType(NeedsFilteredBaseType): @@ -409,6 +411,18 @@ def get_or_create_needs(self) -> dict[str, NeedsInfoType]: self.env.needs_all_needs = {} return self.env.needs_all_needs + @property + def has_export_filters(self) -> bool: + """Whether any filters have export IDs.""" + try: + return self.env.needs_filters_export_id + except AttributeError: + return False + + @has_export_filters.setter + def has_export_filters(self, value: bool) -> None: + self.env.needs_filters_export_id = value + def get_or_create_filters(self) -> dict[str, NeedsFilterType]: """Get all filters, mapped by ID. @@ -593,6 +607,8 @@ def merge_data(_app: Sphinx, env: BuildEnvironment, _docnames: list[str], other: needs = SphinxNeedsData(env).get_or_create_needs() other_needs = SphinxNeedsData(other).get_or_create_needs() needs.update(other_needs) + if SphinxNeedsData(other).has_export_filters: + SphinxNeedsData(env).has_export_filters = True def _merge(name: str, is_complex_dict: bool = False) -> None: # Update global needs dict diff --git a/sphinx_needs/directives/need.py b/sphinx_needs/directives/need.py index 2636f403a..45e2bc1de 100644 --- a/sphinx_needs/directives/need.py +++ b/sphinx_needs/directives/need.py @@ -360,8 +360,32 @@ def previous_sibling(node: nodes.Node) -> Optional[nodes.Node]: return node.parent[i - 1] if i > 0 else None # type: ignore -@profile("NEED_PROCESS") -@measure_time("need") +@profile("NEEDS_POST_PROCESS") +@measure_time("need_post_process") +def post_process_needs_data(app: Sphinx) -> None: + """In-place post-processing of needs data. + + This should be called after all needs (and extend) data has been collected. + + This function is idempotent; + it will only be run on the first call, and will not be run again. + + After this function has been run, one should assume that the needs data is finalised, + and so in principle should be treated as read-only. + """ + needs_config = NeedsSphinxConfig(app.config) + needs_data = SphinxNeedsData(app.env) + needs = needs_data.get_or_create_needs() + if needs and not needs_data.needs_is_post_processed: + extend_needs_data(needs, needs_data.get_or_create_extends(), needs_config) + 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) + needs_data.needs_is_post_processed = True + + def process_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) -> None: """ Event handler to add title meta data (status, tags, links, ...) information to the Need node. Also processes @@ -374,39 +398,23 @@ def process_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str) - node.parent.remove(node) # type: ignore return - env = app.env - needs_data = SphinxNeedsData(env) - needs = needs_data.get_or_create_needs() + needs_data = SphinxNeedsData(app.env) # If no needs were defined, we do not need to do anything - if not needs: + if not needs_data.get_or_create_needs(): return - 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 + post_process_needs_data(app) for extend_node in doctree.findall(Needextend): remove_needextend_node(extend_node) - print_need_nodes(app, doctree, fromdocname, list(doctree.findall(Need))) + format_need_nodes(app, doctree, fromdocname, list(doctree.findall(Need))) -@profile("NEED_PRINT") -def print_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str, found_needs_nodes: List[Need]) -> None: - """ - Finally creates the need-node in the docutils node-tree. - - :param app: - :param doctree: - :param fromdocname: - :return: - """ +@profile("NEED_FORMAT") +def format_need_nodes(app: Sphinx, doctree: nodes.document, fromdocname: str, found_needs_nodes: List[Need]) -> None: + """Replace need nodes in the document with node trees suitable for output""" env = app.env needs = SphinxNeedsData(env).get_or_create_needs() diff --git a/sphinx_needs/directives/needextend.py b/sphinx_needs/directives/needextend.py index fdfc3789a..c6a23732f 100644 --- a/sphinx_needs/directives/needextend.py +++ b/sphinx_needs/directives/needextend.py @@ -75,11 +75,7 @@ def extend_needs_data( ) -> 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) + list_values = ["tags", "links"] + [x["option"] for x in needs_config.extra_links] link_names = [x["option"] for x in needs_config.extra_links] for current_needextend in extends.values(): @@ -114,23 +110,26 @@ def extend_needs_data( 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"]] + if value.strip().startswith("[[") and value.strip().endswith("]]"): # dynamic function + need[option_name].append(value) + else: + 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) 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) + if value.strip().startswith("[[") and value.strip().endswith("]]"): # dynamic function + need[option_name].append(value) + else: + 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 @@ -140,9 +139,6 @@ def extend_needs_data( 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] = [] @@ -150,24 +146,24 @@ def extend_needs_data( 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"]] + if value.strip().startswith("[[") and value.strip().endswith("]]"): # dynamic function + need[option].append(value) + else: + 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) elif option in list_values: - need[option] = [i.strip() for i in re.split(";|,", value)] + if value.strip().startswith("[[") and value.strip().endswith("]]"): # dynamic function + need[option].append(value) + else: + need[option] = [i.strip() for i in re.split(";|,", value)] else: need[option] = value diff --git a/sphinx_needs/directives/needextract.py b/sphinx_needs/directives/needextract.py index dc397a5a5..d77da0ce6 100644 --- a/sphinx_needs/directives/needextract.py +++ b/sphinx_needs/directives/needextract.py @@ -56,7 +56,6 @@ def run(self) -> Sequence[nodes.Node]: "docname": env.docname, "lineno": self.lineno, "target_id": targetid, - "export_id": self.options.get("export_id", ""), "layout": self.options.get("layout"), "style": self.options.get("style"), "show_filters": "show_filters" in self.options, diff --git a/sphinx_needs/directives/needfilter.py b/sphinx_needs/directives/needfilter.py index d1d6326f0..2278b5adf 100644 --- a/sphinx_needs/directives/needfilter.py +++ b/sphinx_needs/directives/needfilter.py @@ -60,7 +60,6 @@ def run(self) -> Sequence[nodes.Node]: "show_filters": "show_filters" in self.options, "show_legend": "show_legend" in self.options, "layout": self.options.get("layout", "list"), - "export_id": self.options.get("export_id", ""), **self.collect_filter_attributes(), } diff --git a/sphinx_needs/directives/needlist.py b/sphinx_needs/directives/needlist.py index ea8979560..53526cb10 100644 --- a/sphinx_needs/directives/needlist.py +++ b/sphinx_needs/directives/needlist.py @@ -50,7 +50,6 @@ def run(self) -> Sequence[nodes.Node]: "show_tags": "show_tags" in self.options, "show_status": "show_status" in self.options, "show_filters": "show_filters" in self.options, - "export_id": self.options.get("export_id", ""), **self.collect_filter_attributes(), } diff --git a/sphinx_needs/environment.py b/sphinx_needs/environment.py index 2b78a170f..943a81bbe 100644 --- a/sphinx_needs/environment.py +++ b/sphinx_needs/environment.py @@ -160,7 +160,7 @@ def install_static_files( def install_lib_static_files(app: Sphinx, env: BuildEnvironment) -> None: """ - Copies ccs and js files from needed js/css libs + Copies css and js files from needed js/css libs :param app: :param env: :return: @@ -186,7 +186,12 @@ def install_lib_static_files(app: Sphinx, env: BuildEnvironment) -> None: # Add the needed datatables js and css file lib_path = Path("sphinx-needs") / "libs" / "html" - for f in ["datatables.min.js", "datatables_loader.js", "datatables.min.css", "sphinx_needs_collapse.js"]: + for f in [ + "datatables.min.js", + "datatables_loader.js", + "datatables.min.css", + "sphinx_needs_collapse.js", + ]: safe_add_file(lib_path / f, app) diff --git a/sphinx_needs/filter_common.py b/sphinx_needs/filter_common.py index 5bab81c0b..1b04bdde2 100644 --- a/sphinx_needs/filter_common.py +++ b/sphinx_needs/filter_common.py @@ -40,6 +40,7 @@ class FilterAttributesType(TypedDict): filter_code: list[str] filter_func: str export_id: str + """If set, the filter is exported with this ID in the needs.json file.""" class FilterBase(SphinxDirective): @@ -74,6 +75,10 @@ def collect_filter_attributes(self) -> FilterAttributesType: if isinstance(types, str): types = [typ.strip() for typ in re.split(";|,", types)] + if self.options.get("export_id", ""): + # this is used by needs builders + SphinxNeedsData(self.env).has_export_filters = True + # Add the need and all needed information collected_filter_options: FilterAttributesType = { "status": status, diff --git a/sphinx_needs/layout.py b/sphinx_needs/layout.py index 887d2fea8..38b123e50 100644 --- a/sphinx_needs/layout.py +++ b/sphinx_needs/layout.py @@ -397,7 +397,7 @@ def _func_replace(self, section_nodes: List[nodes.Node]) -> List[nodes.Node]: node.replace(child, new_child) # type: ignore[attr-defined] return_nodes.append(node) else: - node_str = str(node) + node_str = node.astext() # func_elements = re.findall(r'<<([a-z_()]*)>>', node_str) node_line = nodes.inline() @@ -486,7 +486,11 @@ def meta(self, name: str, prefix: Optional[str] = None, show_empty: bool = False Returns the specific metadata of a need inside docutils nodes. Usage:: - <> + <> + + .. note:: + + You must escape all rst_content in your function strings! E.g. to get `**` one must use `\\\\*\\\\*`. :param name: name of the need item :param prefix: string as rst-code, will be added infront of the value output diff --git a/sphinx_needs/needsfile.py b/sphinx_needs/needsfile.py index 23a06d6fc..b34c8f8e7 100644 --- a/sphinx_needs/needsfile.py +++ b/sphinx_needs/needsfile.py @@ -12,6 +12,7 @@ from jsonschema import Draft7Validator from sphinx.config import Config +from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import NeedsFilterType, NeedsInfoType from sphinx_needs.logging import get_logger @@ -31,6 +32,10 @@ class NeedsList: "hide_tags", "content", "content_node", + # id_parent, id_parent are added on calls to `prepare_need_list` + # but are only relevant to parts + "id_parent", + "id_complete", } JSON_KEY_EXCLUSIONS_FILTERS = { @@ -60,6 +65,10 @@ def __init__(self, config: Config, outdir: str, confdir: str) -> None: "versions": {}, } self.log = log + # also exclude back links for link types dynamically set by the user + back_link_keys = {x["option"] + "_back" for x in NeedsSphinxConfig(config).extra_links} + self._exclude_need_keys = self.JSON_KEY_EXCLUSIONS_NEEDS | back_link_keys + self._exclude_filter_keys = self.JSON_KEY_EXCLUSIONS_FILTERS | back_link_keys def update_or_add_version(self, version: str) -> None: if version not in self.needs_list["versions"].keys(): @@ -78,14 +87,14 @@ def update_or_add_version(self, version: str) -> None: def add_need(self, version: str, need_info: NeedsInfoType) -> None: self.update_or_add_version(version) - writable_needs = {key: need_info[key] for key in need_info if key not in self.JSON_KEY_EXCLUSIONS_NEEDS} # type: ignore[literal-required] + writable_needs = {key: need_info[key] for key in need_info if key not in self._exclude_need_keys} # type: ignore[literal-required] writable_needs["description"] = need_info["content"] self.needs_list["versions"][version]["needs"][need_info["id"]] = writable_needs self.needs_list["versions"][version]["needs_amount"] = len(self.needs_list["versions"][version]["needs"]) def add_filter(self, version: str, need_filter: NeedsFilterType) -> None: self.update_or_add_version(version) - writable_filters = {key: need_filter[key] for key in need_filter if key not in self.JSON_KEY_EXCLUSIONS_FILTERS} # type: ignore[literal-required] + writable_filters = {key: need_filter[key] for key in need_filter if key not in self._exclude_filter_keys} # type: ignore[literal-required] self.needs_list["versions"][version]["filters"][need_filter["export_id"].upper()] = writable_filters self.needs_list["versions"][version]["filters_amount"] = len(self.needs_list["versions"][version]["filters"]) diff --git a/tests/__snapshots__/test_basic_doc.ambr b/tests/__snapshots__/test_basic_doc.ambr index 7f0ae5eb5..cecb75dc6 100644 --- a/tests/__snapshots__/test_basic_doc.ambr +++ b/tests/__snapshots__/test_basic_doc.ambr @@ -34,8 +34,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'ST_001', - 'id_complete': 'ST_001', - 'id_parent': 'ST_001', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -52,8 +50,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -106,8 +102,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'US_38823', - 'id_complete': 'US_38823', - 'id_parent': 'US_38823', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -124,8 +118,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_export_id.ambr b/tests/__snapshots__/test_export_id.ambr index 6f26b2cb8..21855b287 100644 --- a/tests/__snapshots__/test_export_id.ambr +++ b/tests/__snapshots__/test_export_id.ambr @@ -119,9 +119,6 @@ 'blocks': list([ 'REQ_003', ]), - 'blocks_back': list([ - 'REQ_005', - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -143,8 +140,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_001', - 'id_complete': 'REQ_001', - 'id_parent': 'REQ_001', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -164,8 +159,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -188,10 +181,6 @@ 'template': None, 'tests': list([ ]), - 'tests_back': list([ - 'TEST_001', - 'TEST_002', - ]), 'title': 'My requirement', 'type': 'story', 'type_name': 'User Story', @@ -206,8 +195,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -229,8 +216,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_002', - 'id_complete': 'REQ_002', - 'id_parent': 'REQ_002', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -247,8 +232,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -271,8 +254,6 @@ 'template': None, 'tests': list([ ]), - 'tests_back': list([ - ]), 'title': 'My requirement 2', 'type': 'story', 'type_name': 'User Story', @@ -287,9 +268,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - 'REQ_001', - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -311,8 +289,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_003', - 'id_complete': 'REQ_003', - 'id_parent': 'REQ_003', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -329,8 +305,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -353,9 +327,6 @@ 'template': None, 'tests': list([ ]), - 'tests_back': list([ - 'TEST_001', - ]), 'title': 'My requirement 3', 'type': 'story', 'type_name': 'User Story', @@ -370,8 +341,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -393,8 +362,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_004', - 'id_complete': 'REQ_004', - 'id_parent': 'REQ_004', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -411,8 +378,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -435,8 +400,6 @@ 'template': None, 'tests': list([ ]), - 'tests_back': list([ - ]), 'title': 'My requirement 4', 'type': 'story', 'type_name': 'User Story', @@ -452,8 +415,6 @@ 'blocks': list([ 'REQ_001', ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -479,8 +440,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_005', - 'id_complete': 'REQ_005', - 'id_parent': 'REQ_005', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -499,8 +458,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ '1': dict({ 'content': ' awesome part', @@ -552,9 +509,6 @@ 'template': None, 'tests': list([ ]), - 'tests_back': list([ - 'TEST_003', - ]), 'title': 'Req 5', 'type': 'story', 'type_name': 'User Story', @@ -569,8 +523,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -592,8 +544,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'TEST_001', - 'id_complete': 'TEST_001', - 'id_parent': 'TEST_001', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -610,8 +560,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -636,8 +584,6 @@ 'REQ_001', 'REQ_003', ]), - 'tests_back': list([ - ]), 'title': 'Test of requirements', 'type': 'test', 'type_name': 'Test Case', @@ -652,8 +598,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -675,8 +619,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'TEST_002', - 'id_complete': 'TEST_002', - 'id_parent': 'TEST_002', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -694,8 +636,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -719,8 +659,6 @@ 'tests': list([ 'REQ_001', ]), - 'tests_back': list([ - ]), 'title': 'Test of requirements2', 'type': 'test', 'type_name': 'Test Case', @@ -735,8 +673,6 @@ 'avatar': '', 'blocks': list([ ]), - 'blocks_back': list([ - ]), 'closed_at': '', 'completion': '', 'constraints': list([ @@ -758,8 +694,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'TEST_003', - 'id_complete': 'TEST_003', - 'id_parent': 'TEST_003', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -777,8 +711,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -803,8 +735,6 @@ 'REQ_005.1', 'REQ_005.cool', ]), - 'tests_back': list([ - ]), 'title': 'Test of requirements 5', 'type': 'test', 'type_name': 'Test Case', diff --git a/tests/__snapshots__/test_external.ambr b/tests/__snapshots__/test_external.ambr index 04d9a5e6c..1f65036ef 100644 --- a/tests/__snapshots__/test_external.ambr +++ b/tests/__snapshots__/test_external.ambr @@ -34,8 +34,6 @@ '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, @@ -53,8 +51,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -106,8 +102,6 @@ '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, @@ -126,8 +120,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -181,8 +173,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'REQ_1', - 'id_complete': 'REQ_1', - 'id_parent': 'REQ_1', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -199,8 +189,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -253,8 +241,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'SPEC_1', - 'id_complete': 'SPEC_1', - 'id_parent': 'SPEC_1', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -273,8 +259,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -327,8 +311,6 @@ 'has_forbidden_dead_links': '', 'hidden': '', 'id': 'SUB_002', - 'id_complete': 'SUB_002', - 'id_parent': 'SUB_002', 'id_prefix': '', 'is_external': False, 'is_modified': False, @@ -345,8 +327,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_import.ambr b/tests/__snapshots__/test_import.ambr index 017f2081d..16ec802b5 100644 --- a/tests/__snapshots__/test_import.ambr +++ b/tests/__snapshots__/test_import.ambr @@ -51,8 +51,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -122,8 +120,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -195,8 +191,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -266,8 +260,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -337,8 +329,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -408,8 +398,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -478,8 +466,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -550,8 +536,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -626,8 +610,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -699,8 +681,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -770,8 +750,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -849,8 +827,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -921,8 +897,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -993,8 +967,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1063,9 +1035,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - 'T_C3893', - ]), 'parts': dict({ }), 'post_template': None, @@ -1142,8 +1111,6 @@ 'parent_needs': list([ 'T_5CCAA', ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1216,8 +1183,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1291,8 +1256,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1368,8 +1331,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1443,8 +1404,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1518,8 +1477,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1592,8 +1549,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1668,8 +1623,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1748,8 +1701,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1825,8 +1776,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1908,8 +1857,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -1984,8 +1931,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -2060,8 +2005,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -2134,9 +2077,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - 'collapsed_T_C3893', - ]), 'parts': dict({ }), 'post_template': None, @@ -2217,8 +2157,6 @@ 'parent_needs': list([ 'collapsed_T_5CCAA', ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -2296,9 +2234,6 @@ 'parent_needs': list([ 'hidden_TEST_01', ]), - 'parent_needs_back': list([ - 'hidden_OWN_ID_123', - ]), 'parts': dict({ }), 'post_template': None, @@ -2371,9 +2306,6 @@ 'parent_needs': list([ 'hidden_IMPL_01', ]), - 'parent_needs_back': list([ - 'hidden_REQ_001', - ]), 'parts': dict({ }), 'post_template': None, @@ -2448,9 +2380,6 @@ 'parent_needs': list([ 'hidden_OWN_ID_123', ]), - 'parent_needs_back': list([ - 'hidden_ROLES_REQ_1', - ]), 'parts': dict({ }), 'post_template': None, @@ -2523,9 +2452,6 @@ 'parent_needs': list([ 'hidden_REQ_001', ]), - 'parent_needs_back': list([ - 'hidden_ROLES_REQ_2', - ]), 'parts': dict({ }), 'post_template': None, @@ -2598,9 +2524,6 @@ 'parent_needs': list([ 'hidden_ROLES_REQ_1', ]), - 'parent_needs_back': list([ - 'hidden_R_22EB2', - ]), 'parts': dict({ }), 'post_template': None, @@ -2672,9 +2595,6 @@ 'parent_needs': list([ 'hidden_ROLES_REQ_2', ]), - 'parent_needs_back': list([ - 'hidden_R_2A9D0', - ]), 'parts': dict({ }), 'post_template': None, @@ -2748,9 +2668,6 @@ 'parent_needs': list([ 'hidden_R_22EB2', ]), - 'parent_needs_back': list([ - 'hidden_R_F4722', - ]), 'parts': dict({ }), 'post_template': None, @@ -2828,9 +2745,6 @@ 'parent_needs': list([ 'hidden_R_2A9D0', ]), - 'parent_needs_back': list([ - 'hidden_S_01A67', - ]), 'parts': dict({ }), 'post_template': None, @@ -2905,9 +2819,6 @@ 'parent_needs': list([ 'hidden_R_F4722', ]), - 'parent_needs_back': list([ - 'hidden_S_503A1', - ]), 'parts': dict({ }), 'post_template': None, @@ -2988,9 +2899,6 @@ 'parent_needs': list([ 'hidden_S_01A67', ]), - 'parent_needs_back': list([ - 'hidden_S_D70B0', - ]), 'parts': dict({ }), 'post_template': None, @@ -3064,9 +2972,6 @@ 'parent_needs': list([ 'hidden_S_503A1', ]), - 'parent_needs_back': list([ - 'hidden_T_5CCAA', - ]), 'parts': dict({ }), 'post_template': None, @@ -3139,9 +3044,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - 'hidden_IMPL_01', - ]), 'parts': dict({ }), 'post_template': None, @@ -3213,9 +3115,6 @@ 'parent_needs': list([ 'hidden_S_D70B0', ]), - 'parent_needs_back': list([ - 'hidden_T_C3893', - ]), 'parts': dict({ }), 'post_template': None, @@ -3294,8 +3193,6 @@ 'parent_needs': list([ 'hidden_T_5CCAA', ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3369,8 +3266,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3439,8 +3334,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3511,8 +3404,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3583,8 +3474,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3653,8 +3542,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3724,8 +3611,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3798,8 +3683,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3874,8 +3757,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -3948,8 +3829,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4022,8 +3901,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4095,8 +3972,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4170,8 +4045,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4249,8 +4122,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4325,8 +4196,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4407,8 +4276,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4482,8 +4349,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4557,8 +4422,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -4630,9 +4493,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - 'test_T_C3893', - ]), 'parts': dict({ }), 'post_template': None, @@ -4712,8 +4572,6 @@ 'parent_needs': list([ 'test_T_5CCAA', ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_need_constraints.ambr b/tests/__snapshots__/test_need_constraints.ambr index 8334cd384..291821d6e 100644 --- a/tests/__snapshots__/test_need_constraints.ambr +++ b/tests/__snapshots__/test_need_constraints.ambr @@ -50,8 +50,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -125,8 +123,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -202,8 +198,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -276,8 +270,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -346,8 +338,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -423,8 +413,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -500,8 +488,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -574,8 +560,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_needextend.ambr b/tests/__snapshots__/test_needextend.ambr index ca3a866b5..5568efe93 100644 --- a/tests/__snapshots__/test_needextend.ambr +++ b/tests/__snapshots__/test_needextend.ambr @@ -1,4 +1,294 @@ # serializer version: 1 +# name: test_doc_needextend_dynamic[test_app0] + dict({ + 'current_version': '', + 'project': 'Python', + 'versions': dict({ + '': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + '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': 'Requirement 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_1', + 'id_prefix': '', + 'is_external': False, + 'is_modified': True, + 'is_need': True, + 'is_part': False, + 'jinja_content': None, + 'layout': '', + 'links': list([ + 'REQ_A_1', + 'REQ_B_1', + ]), + 'max_amount': '', + 'max_content_lines': '', + 'modifications': 2, + 'params': '', + 'parent_need': '', + 'parent_needs': list([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'needextend dynamic functions', + 'sections': list([ + 'needextend dynamic functions', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_1', + 'template': None, + 'title': 'Requirement 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_A_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_A_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement A 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_A_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([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'needextend dynamic functions', + 'sections': list([ + 'needextend dynamic functions', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_A_1', + 'template': None, + 'title': 'Requirement A 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_B_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_B_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement B 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_B_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([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'needextend dynamic functions', + 'sections': list([ + 'needextend dynamic functions', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_B_1', + 'template': None, + 'title': 'Requirement B 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + 'REQ_C_1': dict({ + 'arch': dict({ + }), + 'avatar': '', + 'closed_at': '', + 'completion': '', + 'constraints': list([ + ]), + 'constraints_passed': True, + 'constraints_results': dict({ + }), + 'content_id': 'REQ_C_1', + 'created_at': '', + 'delete': None, + 'description': '', + 'docname': 'index', + 'doctype': '.rst', + 'duration': '', + 'external_css': 'external_link', + 'external_url': None, + 'full_title': 'Requirement C 1', + 'has_dead_links': '', + 'has_forbidden_dead_links': '', + 'hidden': '', + 'id': 'REQ_C_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([ + ]), + 'parts': dict({ + }), + 'post_template': None, + 'pre_template': None, + 'prefix': '', + 'query': '', + 'section_name': 'needextend dynamic functions', + 'sections': list([ + 'needextend dynamic functions', + ]), + 'service': '', + 'signature': '', + 'specific': '', + 'status': None, + 'style': None, + 'tags': list([ + ]), + 'target_id': 'REQ_C_1', + 'template': None, + 'title': 'Requirement C 1', + 'type': 'req', + 'type_name': 'Requirement', + 'updated_at': '', + 'url': '', + 'url_postfix': '', + 'user': '', + }), + }), + 'needs_amount': 4, + }), + }), + }) +# --- # name: test_doc_needextend_html[test_app0] dict({ 'current_version': '', @@ -54,8 +344,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -127,8 +415,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -200,8 +486,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -272,8 +556,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -345,8 +627,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -415,8 +695,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_needs_builder.ambr b/tests/__snapshots__/test_needs_builder.ambr index e3cf93b71..aeec107f6 100644 --- a/tests/__snapshots__/test_needs_builder.ambr +++ b/tests/__snapshots__/test_needs_builder.ambr @@ -50,8 +50,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -120,8 +118,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, @@ -190,8 +186,6 @@ 'parent_need': '', 'parent_needs': list([ ]), - 'parent_needs_back': list([ - ]), 'parts': dict({ }), 'post_template': None, diff --git a/tests/__snapshots__/test_needs_id_builder.ambr b/tests/__snapshots__/test_needs_id_builder.ambr new file mode 100644 index 000000000..9e45b666d --- /dev/null +++ b/tests/__snapshots__/test_needs_id_builder.ambr @@ -0,0 +1,252 @@ +# serializer version: 1 +# name: test_doc_needs_id_builder[test_app0] + dict({ + 'TC_001.json': 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([ + ]), + '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': '', + }), + }), + 'needs_amount': 1, + }), + }), + }), + 'TC_NEG_001.json': dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + '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([ + ]), + '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': '', + }), + }), + 'needs_amount': 1, + }), + }), + }), + 'US_63252.json': dict({ + 'current_version': '1.0', + 'project': 'Python', + 'versions': dict({ + '1.0': dict({ + 'filters': dict({ + }), + 'filters_amount': 0, + 'needs': dict({ + '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([ + ]), + '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': 1, + }), + }), + }), + }) +# --- diff --git a/tests/conftest.py b/tests/conftest.py index c620eabcc..e83e10911 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,55 +1,262 @@ """Pytest conftest module containing common test configuration and fixtures.""" +import json +import os.path +import secrets import shutil -from tempfile import mkdtemp +import socket +import string +import tempfile +from pathlib import Path +from typing import Any, Dict import pytest from docutils.nodes import document +from sphinx.application import Sphinx from sphinx.testing.path import path from syrupy.extensions.single_file import SingleFileSnapshotExtension, WriteMode +from xprocess import ProcessStarter pytest_plugins = "sphinx.testing.fixtures" -def copy_srcdir_to_tmpdir(srcdir, tmp): +def generate_random_string() -> str: + """ + Generate a random string of 10 characters consisting of letters (both uppercase and lowercase) and digits. + + :return: A random string. + """ + characters = string.ascii_letters + string.digits + return "".join(secrets.choice(characters) for i in range(10)) + + +def copy_srcdir_to_tmpdir(srcdir: path, tmp: path) -> path: + """ + Copy Source Directory to Temporary Directory. + + This function copies the contents of a source directory to a temporary + directory. It generates a random subdirectory within the temporary directory + to avoid conflicts and enable parallel processes to run without conflicts. + + :param srcdir: Path to the source directory. + :param tmp: Path to the temporary directory. + + :return: Path to the newly created directory in the temporary directory. + """ srcdir = path(__file__).parent.abspath() / srcdir - tmproot = tmp / path(srcdir).basename() + tmproot = tmp.joinpath(generate_random_string()) / path(srcdir).basename() shutil.copytree(srcdir, tmproot) return tmproot -@pytest.fixture(scope="function") -def test_app(make_app, request): +def get_abspath(relpath: str) -> str: + """ + Get the absolute path from a relative path. + + This function returns an absolute path relative to the conftest.py file. + + :param relpath: The relative path to convert. + :return: The absolute path, or the input if it's not a valid relative path. + """ + if isinstance(relpath, str) and relpath: + abspath = Path(__file__).parent.joinpath(relpath).resolve() + return str(abspath) + return relpath + + +@pytest.fixture(scope="session") +def test_server(xprocess, sphinx_test_tempdir): + """ + Fixture to start and manage the test server process. + + :param sphinx_test_tempdir: The directory to serve. + :return: Information about the server process. + """ + addr = "127.0.0.1" + port = 62343 + + class Starter(ProcessStarter): + pattern = "Serving HTTP on [0-9.]+ port 62343|Address already in use" + timeout = 20 + terminate_on_interrupt = True + args = ["python3", "-m", "http.server", "--directory", sphinx_test_tempdir, "--bind", addr, port] + env = {"PYTHONUNBUFFERED": "1"} + + def check_server_connection(log_path: str): + """ + Checks the connection status to a server. + + :param log_path: The path to the log file. + :return: True if the server connection is successful, False otherwise. + """ + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + result = sock.connect_ex((addr, port)) + sock.close() + if result == 0: + with open(str(log_path), "wb", 0) as stdout: + stdout.write(bytes("Serving HTTP on 127.0.0.1 port 62343 (http://127.0.0.1:62343/) ...\n", "utf8")) + return True + return False + + if not check_server_connection(log_path=xprocess.getinfo("http_server").logpath): + # Start the process and ensure it is running + _, logfile = xprocess.ensure("http_server", Starter, persist_logs=False) # noqa:F841 + + http_server_process = xprocess.getinfo("http_server") + server_url = f"http://{addr}:{port}" + http_server_process.url = server_url + + yield http_server_process + + # clean up whole process tree afterward + xprocess.getinfo("http_server").terminate() + + +def test_js(self) -> Dict[str, Any]: + """ + Executes Cypress tests using the specified `spec_pattern`. + + :param self: An instance of the :class:`Sphinx` application object this function is bounded to. + :return: A dictionary with test execution information. + Keys: + - 'returncode': Return code of the Cypress test execution. + - 'stdout': Standard output of the Cypress test execution. + - 'stderr': Standard error of the Cypress test execution. + """ + cypress_testpath = get_abspath(self.spec_pattern) + + if not cypress_testpath or not (os.path.isabs(cypress_testpath) and os.path.exists(cypress_testpath)): + return { + "returncode": 1, + "stdout": None, + "stderr": f"The spec_pattern '{self.spec_pattern}' cannot be found.", + } + _, out_dir = str(self.outdir).split("sn_test_build_data") + srcdir_url = f"http://127.0.0.1:62343/{out_dir.lstrip('/')}/" + js_test_config = { + "specPattern": cypress_testpath, + "supportFile": get_abspath("js_test/cypress/support/e2e.js"), + "fixturesFolder": False, + "baseUrl": srcdir_url, + } + + cypress_config = json.dumps(js_test_config) + cypress_config_file = get_abspath("js_test/cypress.config.js") + + try: + import subprocess + + # Run the Cypress test command + completed_process = subprocess.run( + [ + "npx", + "cypress", + "run", + # "--browser", + # "chrome", + "--config-file", + rf"{cypress_config_file}", + "--config", + rf"{cypress_config}", + ], + capture_output=True, + ) + + # Send back return code, stdout, and stderr + return { + "returncode": completed_process.returncode, + "stdout": completed_process.stdout, + "stderr": completed_process.stderr, + } + except (Exception, subprocess.CalledProcessError) as e: + return { + "returncode": 1, + "stdout": "", + "stderr": e, + } + + +@pytest.fixture(scope="session") +def sphinx_test_tempdir() -> path: + """ + Fixture to provide a temporary directory for Sphinx testing. + + This function creates a custom temporary folder to avoid potential conflicts + with utility functions from Sphinx and pytest. + + :return Path: Path object representing the temporary directory. + """ # We create a temp-folder on our own, as the util-functions from sphinx and pytest make troubles. # It seems like they reuse certain-temp names - sphinx_test_tempdir = path(mkdtemp()) + sphinx_test_tempdir = path(tempfile.gettempdir()).joinpath("sn_test_build_data") + utils_dir = sphinx_test_tempdir.joinpath("utils") - builder_params = request.param + # if not (sphinx_test_tempdir.exists() and sphinx_test_tempdir.isdir()): + sphinx_test_tempdir.makedirs(exist_ok=True) + # if not (utils_dir.exists() and utils_dir.isdir()): + utils_dir.makedirs(exist_ok=True) - # copy plantuml.jar to current test temdir + # copy plantuml.jar to current test tempdir. We want to do this once + # since the same plantuml.jar is used for each test plantuml_jar_file = path(__file__).parent.abspath() / "doc_test/utils" - shutil.copytree(plantuml_jar_file, sphinx_test_tempdir / "utils") + shutil.copytree(plantuml_jar_file, utils_dir, dirs_exist_ok=True) + + return sphinx_test_tempdir + + +@pytest.fixture(scope="function") +def test_app(make_app, sphinx_test_tempdir, request): + """ + Fixture for creating a Sphinx application for testing. + + This fixture creates a Sphinx application with specified builder parameters and + config overrides. It also copies the test source directory to the test temporary + directory. The fixture yields the Sphinx application, and cleans up the temporary + source directory after the test function has executed. + + :param make_app: A fixture for creating Sphinx applications. + :param sphinx_test_tempdir: A fixture for providing the Sphinx test temporary directory. + :param request: A pytest request object for accessing fixture parameters. + + :return: A Sphinx application object. + """ + builder_params = request.param + + sphinx_conf_overrides = builder_params.get("confoverrides", {}) + # Since we don't want copy the plantuml.jar file for each test function, + # we need to override the plantuml conf variable and set it to what we have already + plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join(sphinx_test_tempdir, "utils", "plantuml.jar") + sphinx_conf_overrides.update(plantuml=plantuml) # copy test srcdir to test temporary directory sphinx_test_tempdir srcdir = builder_params.get("srcdir") src_dir = copy_srcdir_to_tmpdir(srcdir, sphinx_test_tempdir) - # return sphinx.testing fixture make_app and new srcdir which in sphinx_test_tempdir - app = make_app( + # return sphinx.testing fixture make_app and new srcdir which is in sphinx_test_tempdir + app: Sphinx = make_app( buildername=builder_params.get("buildername", "html"), srcdir=src_dir, freshenv=builder_params.get("freshenv"), - confoverrides=builder_params.get("confoverrides"), + confoverrides=sphinx_conf_overrides, status=builder_params.get("status"), warning=builder_params.get("warning"), tags=builder_params.get("tags"), docutilsconf=builder_params.get("docutilsconf"), parallel=builder_params.get("parallel", 0), ) + # Add the spec_pattern as an attribute to the Sphinx app object + app.spec_pattern = builder_params.get("spec_pattern", "*.cy.js") + # Add the ``test_js`` function as an attribute to the Sphinx app object + # This is done by accessing the special method ``__get__`` which allows the ``test_js`` function + # to be bound to the Sphinx app object, enabling it to access the object's attributes. + # We can later call ``test_js`` function as an attribute of the Sphinx app object. + # Since we've bound the ``test_js`` function to the Sphinx object using ``__get__``, + # ``test_js`` behaves like a method. + app.test_js = test_js.__get__(app, Sphinx) yield app - # cleanup test temporary directory - shutil.rmtree(sphinx_test_tempdir, False) + # Clean up the srcdir of each Sphinx app after the test function has executed + shutil.rmtree(src_dir.parent.abspath(), ignore_errors=True) class DoctreeSnapshotExtension(SingleFileSnapshotExtension): diff --git a/tests/doc_test/add_sections/conf.py b/tests/doc_test/add_sections/conf.py index 26e38c1ad..c684207da 100644 --- a/tests/doc_test/add_sections/conf.py +++ b/tests/doc_test/add_sections/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_extra_options = { "introduced": directives.unchanged, "updated": directives.unchanged, diff --git a/tests/doc_test/api_doc/conf.py b/tests/doc_test/api_doc/conf.py index b177eff0c..7832f346d 100644 --- a/tests/doc_test/api_doc/conf.py +++ b/tests/doc_test/api_doc/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs", "dummy_extension.dummy"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/api_doc_awesome/conf.py b/tests/doc_test/api_doc_awesome/conf.py index b177eff0c..7832f346d 100644 --- a/tests/doc_test/api_doc_awesome/conf.py +++ b/tests/doc_test/api_doc_awesome/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs", "dummy_extension.dummy"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/arch_doc/conf.py b/tests/doc_test/arch_doc/conf.py index a98223d82..1571c763f 100644 --- a/tests/doc_test/arch_doc/conf.py +++ b/tests/doc_test/arch_doc/conf.py @@ -1,10 +1,5 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_types = [ diff --git a/tests/doc_test/broken_doc/conf.py b/tests/doc_test/broken_doc/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/broken_doc/conf.py +++ b/tests/doc_test/broken_doc/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/broken_links/conf.py b/tests/doc_test/broken_links/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/broken_links/conf.py +++ b/tests/doc_test/broken_links/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/broken_statuses/conf.py b/tests/doc_test/broken_statuses/conf.py index 4d832f461..3706ca5ff 100644 --- a/tests/doc_test/broken_statuses/conf.py +++ b/tests/doc_test/broken_statuses/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/broken_syntax_doc/conf.py b/tests/doc_test/broken_syntax_doc/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/broken_syntax_doc/conf.py +++ b/tests/doc_test/broken_syntax_doc/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/broken_tags/conf.py b/tests/doc_test/broken_tags/conf.py index 74231fd88..7c04d916c 100644 --- a/tests/doc_test/broken_tags/conf.py +++ b/tests/doc_test/broken_tags/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/broken_tags_2/conf.py b/tests/doc_test/broken_tags_2/conf.py index 74231fd88..7c04d916c 100644 --- a/tests/doc_test/broken_tags_2/conf.py +++ b/tests/doc_test/broken_tags_2/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_basic/conf.py b/tests/doc_test/doc_basic/conf.py index 13694c5cd..0a5cb1761 100644 --- a/tests/doc_test/doc_basic/conf.py +++ b/tests/doc_test/doc_basic/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Za-z0-9_]" diff --git a/tests/doc_test/doc_basic_latex/conf.py b/tests/doc_test/doc_basic_latex/conf.py index ac6f89ce9..32f8e8de5 100644 --- a/tests/doc_test/doc_basic_latex/conf.py +++ b/tests/doc_test/doc_basic_latex/conf.py @@ -1,12 +1,8 @@ -import os - project = "basic test" extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Za-z0-9_]" diff --git a/tests/doc_test/doc_build_latex/conf.py b/tests/doc_test/doc_build_latex/conf.py index 5aa8650a3..6a81ad4bb 100644 --- a/tests/doc_test/doc_build_latex/conf.py +++ b/tests/doc_test/doc_build_latex/conf.py @@ -1,12 +1,8 @@ -import os - project = "needs test docs" extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" # figures, tables and code-blocks are automatically numbered if they have a caption diff --git a/tests/doc_test/doc_df_calc_sum/conf.py b/tests/doc_test/doc_df_calc_sum/conf.py index 0d9612327..2e1bb2cf3 100644 --- a/tests/doc_test/doc_df_calc_sum/conf.py +++ b/tests/doc_test/doc_df_calc_sum/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_df_check_linked_values/conf.py b/tests/doc_test/doc_df_check_linked_values/conf.py index f8894d720..707f3afad 100644 --- a/tests/doc_test/doc_df_check_linked_values/conf.py +++ b/tests/doc_test/doc_df_check_linked_values/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_df_user_functions/conf.py b/tests/doc_test/doc_df_user_functions/conf.py index 769162f8f..07958c0c0 100644 --- a/tests/doc_test/doc_df_user_functions/conf.py +++ b/tests/doc_test/doc_df_user_functions/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_dynamic_functions/conf.py b/tests/doc_test/doc_dynamic_functions/conf.py index eb9084a19..5097fc12d 100644 --- a/tests/doc_test/doc_dynamic_functions/conf.py +++ b/tests/doc_test/doc_dynamic_functions/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_export_id/conf.py b/tests/doc_test/doc_export_id/conf.py index fb7ffd634..34095785f 100644 --- a/tests/doc_test/doc_export_id/conf.py +++ b/tests/doc_test/doc_export_id/conf.py @@ -1,12 +1,8 @@ -import os - version = "1.0" extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_types = [ diff --git a/tests/doc_test/doc_extra_links/conf.py b/tests/doc_test/doc_extra_links/conf.py index b2b0e1a1b..ad8a7f24e 100644 --- a/tests/doc_test/doc_extra_links/conf.py +++ b/tests/doc_test/doc_extra_links/conf.py @@ -1,12 +1,8 @@ -import os - project = "needs test docs" extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_types = [ diff --git a/tests/doc_test/doc_github_issue_160/conf.py b/tests/doc_test/doc_github_issue_160/conf.py index b3702e97f..25247cd89 100644 --- a/tests/doc_test/doc_github_issue_160/conf.py +++ b/tests/doc_test/doc_github_issue_160/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Z0-9]-[A-Z0-9]+" diff --git a/tests/doc_test/doc_github_issue_21/conf.py b/tests/doc_test/doc_github_issue_21/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/doc_github_issue_21/conf.py +++ b/tests/doc_test/doc_github_issue_21/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_github_issue_44/conf.py b/tests/doc_test/doc_github_issue_44/conf.py index 15bcd7517..df3fe57f8 100644 --- a/tests/doc_test/doc_github_issue_44/conf.py +++ b/tests/doc_test/doc_github_issue_44/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_id_regex = "^[A-Za-z0-9_]" needs_types = [ diff --git a/tests/doc_test/doc_github_issue_61/conf.py b/tests/doc_test/doc_github_issue_61/conf.py index b3702e97f..25247cd89 100644 --- a/tests/doc_test/doc_github_issue_61/conf.py +++ b/tests/doc_test/doc_github_issue_61/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Z0-9]-[A-Z0-9]+" diff --git a/tests/doc_test/doc_global_options/conf.py b/tests/doc_test/doc_global_options/conf.py index 88a32691d..46408adc5 100644 --- a/tests/doc_test/doc_global_options/conf.py +++ b/tests/doc_test/doc_global_options/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_layout/conf.py b/tests/doc_test/doc_layout/conf.py index 5bc569c33..6969f1c23 100644 --- a/tests/doc_test/doc_layout/conf.py +++ b/tests/doc_test/doc_layout/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, @@ -30,6 +23,13 @@ "side": ['<>'], }, }, + "optional_author": { + "grid": "simple", + "layout": { + "head": ['**<>**'], + "meta": ['**status**: <>', r'<>'], + }, + }, "footer_grid": { "grid": "simple_footer", "layout": { diff --git a/tests/doc_test/doc_layout/index.rst b/tests/doc_test/doc_layout/index.rst index a34a4dac5..ce1cf38ea 100644 --- a/tests/doc_test/doc_layout/index.rst +++ b/tests/doc_test/doc_layout/index.rst @@ -13,5 +13,9 @@ TEST DOCUMENT .. spec:: title_example_layout :layout: example +.. spec:: title_layout_optional_author + :layout: optional_author + :author: some author + .. spec:: title_layout_footer_grid :layout: footer_grid diff --git a/tests/doc_test/doc_list2need/conf.py b/tests/doc_test/doc_list2need/conf.py index 4805621e5..009477a1b 100644 --- a/tests/doc_test/doc_list2need/conf.py +++ b/tests/doc_test/doc_list2need/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_table_style = "TABLE" diff --git a/tests/doc_test/doc_measure_time/conf.py b/tests/doc_test/doc_measure_time/conf.py index 87be107ad..74f164462 100644 --- a/tests/doc_test/doc_measure_time/conf.py +++ b/tests/doc_test/doc_measure_time/conf.py @@ -9,9 +9,7 @@ extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_debug_measurement = True diff --git a/tests/doc_test/doc_need_count/conf.py b/tests/doc_test/doc_need_count/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/doc_need_count/conf.py +++ b/tests/doc_test/doc_need_count/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_need_delete/conf.py b/tests/doc_test/doc_need_delete/conf.py index 76c7bb1b8..104609b54 100644 --- a/tests/doc_test/doc_need_delete/conf.py +++ b/tests/doc_test/doc_need_delete/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Za-z0-9_]" diff --git a/tests/doc_test/doc_need_id_from_title/conf.py b/tests/doc_test/doc_need_id_from_title/conf.py index b7134f2fc..e3a53e73b 100644 --- a/tests/doc_test/doc_need_id_from_title/conf.py +++ b/tests/doc_test/doc_need_id_from_title/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_need_jinja_content/conf.py b/tests/doc_test/doc_need_jinja_content/conf.py index 11dbcbd5c..3f7d3cdd7 100644 --- a/tests/doc_test/doc_need_jinja_content/conf.py +++ b/tests/doc_test/doc_need_jinja_content/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_id_regex = "^[A-Za-z0-9_]" diff --git a/tests/doc_test/doc_need_parts/conf.py b/tests/doc_test/doc_need_parts/conf.py index 5669e9b09..21eab6d52 100644 --- a/tests/doc_test/doc_need_parts/conf.py +++ b/tests/doc_test/doc_need_parts/conf.py @@ -1,12 +1,5 @@ -import os - extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, diff --git a/tests/doc_test/doc_needarch/conf.py b/tests/doc_test/doc_needarch/conf.py index 6a4ac75e9..1666acffc 100644 --- a/tests/doc_test/doc_needarch/conf.py +++ b/tests/doc_test/doc_needarch/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_table_style = "TABLE" diff --git a/tests/doc_test/doc_needarch_jinja_func_import/conf.py b/tests/doc_test/doc_needarch_jinja_func_import/conf.py index facceaa58..dfccf97c2 100644 --- a/tests/doc_test/doc_needarch_jinja_func_import/conf.py +++ b/tests/doc_test/doc_needarch_jinja_func_import/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_types = [ diff --git a/tests/doc_test/doc_needarch_jinja_func_need/conf.py b/tests/doc_test/doc_needarch_jinja_func_need/conf.py index 6a4ac75e9..1666acffc 100644 --- a/tests/doc_test/doc_needarch_jinja_func_need/conf.py +++ b/tests/doc_test/doc_needarch_jinja_func_need/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_table_style = "TABLE" diff --git a/tests/doc_test/doc_needarch_negative_tests/conf.py b/tests/doc_test/doc_needarch_negative_tests/conf.py index 6a4ac75e9..1666acffc 100644 --- a/tests/doc_test/doc_needarch_negative_tests/conf.py +++ b/tests/doc_test/doc_needarch_negative_tests/conf.py @@ -1,10 +1,6 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" needs_table_style = "TABLE" diff --git a/tests/doc_test/doc_needextend/conf.py b/tests/doc_test/doc_needextend/conf.py index 7f111502f..08df9747f 100644 --- a/tests/doc_test/doc_needextend/conf.py +++ b/tests/doc_test/doc_needextend/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_build_json = True @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needextend_dynamic/conf.py b/tests/doc_test/doc_needextend_dynamic/conf.py new file mode 100644 index 000000000..87580e5f4 --- /dev/null +++ b/tests/doc_test/doc_needextend_dynamic/conf.py @@ -0,0 +1,13 @@ +extensions = ["sphinx_needs"] +needs_build_json = True + + +def get_matching_need_ids(app, need, needs, id_prefix=""): + filtered_needs = [] + for need_id, _ in needs.items(): + if id_prefix and need_id.startswith(id_prefix): + filtered_needs.append(need_id) + return filtered_needs + + +needs_functions = [get_matching_need_ids] diff --git a/tests/doc_test/doc_needextend_dynamic/index.rst b/tests/doc_test/doc_needextend_dynamic/index.rst new file mode 100644 index 000000000..17ba8911c --- /dev/null +++ b/tests/doc_test/doc_needextend_dynamic/index.rst @@ -0,0 +1,20 @@ +needextend dynamic functions +============================ + +.. req:: Requirement 1 + :id: REQ_1 + +.. req:: Requirement A 1 + :id: REQ_A_1 + +.. req:: Requirement B 1 + :id: REQ_B_1 + +.. req:: Requirement C 1 + :id: REQ_C_1 + +.. needextend:: REQ_1 + :links: [[get_matching_need_ids("REQ_A_")]] + +.. needextend:: REQ_1 + :+links: [[get_matching_need_ids("REQ_B_")]] diff --git a/tests/doc_test/doc_needextend_strict/conf.py b/tests/doc_test/doc_needextend_strict/conf.py index 4e7116d36..6b4b9fa9d 100644 --- a/tests/doc_test/doc_needextend_strict/conf.py +++ b/tests/doc_test/doc_needextend_strict/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]*" @@ -9,8 +7,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needextract/conf.py b/tests/doc_test/doc_needextract/conf.py index c71f0ce23..47badfa7d 100644 --- a/tests/doc_test/doc_needextract/conf.py +++ b/tests/doc_test/doc_needextract/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] rst_prolog = """ @@ -15,8 +13,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needflow/conf.py b/tests/doc_test/doc_needflow/conf.py index 5ff80aeaa..aa6219420 100644 --- a/tests/doc_test/doc_needflow/conf.py +++ b/tests/doc_test/doc_needflow/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_id_regex = "^[A-Za-z0-9_]" @@ -12,8 +13,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needflow_incl_child_needs/conf.py b/tests/doc_test/doc_needflow_incl_child_needs/conf.py index d6c00f39e..24b1cbd1b 100644 --- a/tests/doc_test/doc_needflow_incl_child_needs/conf.py +++ b/tests/doc_test/doc_needflow_incl_child_needs/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_id_regex = "^[A-Za-z0-9_]" @@ -27,9 +28,3 @@ # "allow_dead_links": True, # }, # ] - - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needimport_download_needs_json/conf.py b/tests/doc_test/doc_needimport_download_needs_json/conf.py index 6c0a46f6b..885bd47d6 100644 --- a/tests/doc_test/doc_needimport_download_needs_json/conf.py +++ b/tests/doc_test/doc_needimport_download_needs_json/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needimport_download_needs_json_negative/conf.py b/tests/doc_test/doc_needimport_download_needs_json_negative/conf.py index 6c0a46f6b..885bd47d6 100644 --- a/tests/doc_test/doc_needimport_download_needs_json_negative/conf.py +++ b/tests/doc_test/doc_needimport_download_needs_json_negative/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needimport_noindex/conf.py b/tests/doc_test/doc_needimport_noindex/conf.py index bce8665e6..e9342e0ea 100644 --- a/tests/doc_test/doc_needimport_noindex/conf.py +++ b/tests/doc_test/doc_needimport_noindex/conf.py @@ -1,5 +1,3 @@ -import os - project = "needs test docs" master_doc = "intro" @@ -8,8 +6,5 @@ # figures, tables and code-blocks are automatically numbered if they have a caption numfig = True - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) +# note, the plantuml executable command is set globally in the test suite plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needlist/conf.py b/tests/doc_test/doc_needlist/conf.py index 6c0a46f6b..885bd47d6 100644 --- a/tests/doc_test/doc_needlist/conf.py +++ b/tests/doc_test/doc_needlist/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needpie/conf.py b/tests/doc_test/doc_needpie/conf.py index 98640e4e8..86ef3ff45 100644 --- a/tests/doc_test/doc_needpie/conf.py +++ b/tests/doc_test/doc_needpie/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_id_regex = "^[A-Za-z0-9_]" @@ -14,8 +15,3 @@ ] needs_extra_options = ["author"] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needs_builder/conf.py b/tests/doc_test/doc_needs_builder/conf.py index 09eddcb8e..ce1cbf2cf 100644 --- a/tests/doc_test/doc_needs_builder/conf.py +++ b/tests/doc_test/doc_needs_builder/conf.py @@ -1,5 +1,3 @@ -import os - version = "1.0" extensions = ["sphinx_needs"] @@ -13,9 +11,4 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_file = "custom_needs_test.json" diff --git a/tests/doc_test/doc_needs_builder_negative_tests/conf.py b/tests/doc_test/doc_needs_builder_negative_tests/conf.py index 6c0a46f6b..885bd47d6 100644 --- a/tests/doc_test/doc_needs_builder_negative_tests/conf.py +++ b/tests/doc_test/doc_needs_builder_negative_tests/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needs_builder_parallel/conf.py b/tests/doc_test/doc_needs_builder_parallel/conf.py index 268a11ca3..87abb2f42 100644 --- a/tests/doc_test/doc_needs_builder_parallel/conf.py +++ b/tests/doc_test/doc_needs_builder_parallel/conf.py @@ -1,5 +1,3 @@ -import os - version = "1.0" extensions = ["sphinx_needs"] @@ -15,9 +13,4 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_file = "custom_needs_test.json" diff --git a/tests/doc_test/doc_needs_external_needs/conf.py b/tests/doc_test/doc_needs_external_needs/conf.py index be8231d5c..95e5cee80 100644 --- a/tests/doc_test/doc_needs_external_needs/conf.py +++ b/tests/doc_test/doc_needs_external_needs/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -11,11 +12,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ {"base_url": "http://my_company.com/docs/v1/", "json_path": "needs_test_small.json", "id_prefix": "ext_"}, {"base_url": "../../_build/html", "json_path": "needs_test_small.json", "id_prefix": "ext_rel_path_"}, diff --git a/tests/doc_test/doc_needs_external_needs_remote/conf.py b/tests/doc_test/doc_needs_external_needs_remote/conf.py index 9f242fa1d..b63ea602c 100644 --- a/tests/doc_test/doc_needs_external_needs_remote/conf.py +++ b/tests/doc_test/doc_needs_external_needs_remote/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -11,11 +12,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ { "base_url": "http://my_company.com/docs/v1/", diff --git a/tests/doc_test/doc_needs_external_needs_with_target_url/conf.py b/tests/doc_test/doc_needs_external_needs_with_target_url/conf.py index 0e094cd55..d4c198d2d 100644 --- a/tests/doc_test/doc_needs_external_needs_with_target_url/conf.py +++ b/tests/doc_test/doc_needs_external_needs_with_target_url/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -11,11 +12,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ { "base_url": "http://my_company.com/docs/v1/", diff --git a/tests/doc_test/doc_needs_filter_data/conf.py b/tests/doc_test/doc_needs_filter_data/conf.py index bd9178810..23aa68579 100644 --- a/tests/doc_test/doc_needs_filter_data/conf.py +++ b/tests/doc_test/doc_needs_filter_data/conf.py @@ -7,6 +7,9 @@ extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_id_regex = "^[A-Za-z0-9_]*" needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, @@ -31,8 +34,3 @@ def custom_func(): } needs_warnings_always_warn = True - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needs_warnings/conf.py b/tests/doc_test/doc_needs_warnings/conf.py index 0e1c50c45..f6b991773 100644 --- a/tests/doc_test/doc_needs_warnings/conf.py +++ b/tests/doc_test/doc_needs_warnings/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -11,11 +9,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ {"base_url": "http://my_company.com/docs/v1/", "json_path": "needs_test_small.json", "id_prefix": "ext_"} ] diff --git a/tests/doc_test/doc_needs_warnings_return_status_code/conf.py b/tests/doc_test/doc_needs_warnings_return_status_code/conf.py index 3f9415d79..490cb7534 100644 --- a/tests/doc_test/doc_needs_warnings_return_status_code/conf.py +++ b/tests/doc_test/doc_needs_warnings_return_status_code/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -11,11 +9,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - def my_custom_warning_check(need, log): if need["status"] == "open": diff --git a/tests/doc_test/doc_needsfile/conf.py b/tests/doc_test/doc_needsfile/conf.py index d3d4bf6ef..e607e1f34 100644 --- a/tests/doc_test/doc_needsfile/conf.py +++ b/tests/doc_test/doc_needsfile/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_file = "needs_errors.json" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needtable/conf.py b/tests/doc_test/doc_needtable/conf.py index 4cf02a484..585e4438d 100644 --- a/tests/doc_test/doc_needtable/conf.py +++ b/tests/doc_test/doc_needtable/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -41,8 +39,3 @@ "options": ["github"], }, } - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml/conf.py b/tests/doc_test/doc_needuml/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml/conf.py +++ b/tests/doc_test/doc_needuml/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_diagram_allowmixing/conf.py b/tests/doc_test/doc_needuml_diagram_allowmixing/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_diagram_allowmixing/conf.py +++ b/tests/doc_test/doc_needuml_diagram_allowmixing/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_duplicate_key/conf.py b/tests/doc_test/doc_needuml_duplicate_key/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_duplicate_key/conf.py +++ b/tests/doc_test/doc_needuml_duplicate_key/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_filter/conf.py b/tests/doc_test/doc_needuml_filter/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_filter/conf.py +++ b/tests/doc_test/doc_needuml_filter/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_jinja_func_flow/conf.py b/tests/doc_test/doc_needuml_jinja_func_flow/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_jinja_func_flow/conf.py +++ b/tests/doc_test/doc_needuml_jinja_func_flow/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_jinja_func_import_negative_tests/conf.py b/tests/doc_test/doc_needuml_jinja_func_import_negative_tests/conf.py index 1ddbd80a9..dfccf97c2 100644 --- a/tests/doc_test/doc_needuml_jinja_func_import_negative_tests/conf.py +++ b/tests/doc_test/doc_needuml_jinja_func_import_negative_tests/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_types = [ { "directive": "int", @@ -34,11 +35,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_extra_links = [ { "option": "uses", diff --git a/tests/doc_test/doc_needuml_jinja_func_need_removed/conf.py b/tests/doc_test/doc_needuml_jinja_func_need_removed/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_jinja_func_need_removed/conf.py +++ b/tests/doc_test/doc_needuml_jinja_func_need_removed/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_jinja_func_ref/conf.py b/tests/doc_test/doc_needuml_jinja_func_ref/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_jinja_func_ref/conf.py +++ b/tests/doc_test/doc_needuml_jinja_func_ref/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_key_name_diagram/conf.py b/tests/doc_test/doc_needuml_key_name_diagram/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_key_name_diagram/conf.py +++ b/tests/doc_test/doc_needuml_key_name_diagram/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_needuml_save/conf.py b/tests/doc_test/doc_needuml_save/conf.py index 3b01b0e60..e4c6437fd 100644 --- a/tests/doc_test/doc_needuml_save/conf.py +++ b/tests/doc_test/doc_needuml_save/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -36,9 +37,4 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_build_needumls = "my_needumls" diff --git a/tests/doc_test/doc_needuml_save_with_abs_path/conf.py b/tests/doc_test/doc_needuml_save_with_abs_path/conf.py index 646739a08..1666acffc 100644 --- a/tests/doc_test/doc_needuml_save_with_abs_path/conf.py +++ b/tests/doc_test/doc_needuml_save_with_abs_path/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_table_style = "TABLE" needs_types = [ @@ -35,8 +36,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_open_needs_service/conf.py b/tests/doc_test/doc_open_needs_service/conf.py index 9d5f42fd3..be86e0012 100644 --- a/tests/doc_test/doc_open_needs_service/conf.py +++ b/tests/doc_test/doc_open_needs_service/conf.py @@ -29,9 +29,3 @@ }, }, } - - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_report_dead_links_false/conf.py b/tests/doc_test/doc_report_dead_links_false/conf.py index a2d0203e1..3e75ba02f 100644 --- a/tests/doc_test/doc_report_dead_links_false/conf.py +++ b/tests/doc_test/doc_report_dead_links_false/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, @@ -29,8 +30,3 @@ "style_part": "dotted,#00AA00", }, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_report_dead_links_true/conf.py b/tests/doc_test/doc_report_dead_links_true/conf.py index c48c0e9db..91467f963 100644 --- a/tests/doc_test/doc_report_dead_links_true/conf.py +++ b/tests/doc_test/doc_report_dead_links_true/conf.py @@ -1,7 +1,8 @@ -import os - extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_types = [ {"directive": "story", "title": "User Story", "prefix": "US_", "color": "#BFD8D2", "style": "node"}, {"directive": "spec", "title": "Specification", "prefix": "SP_", "color": "#FEDCD2", "style": "node"}, @@ -27,8 +28,3 @@ "style_part": "dotted,#00AA00", }, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_role_need_max_title_length/conf.py b/tests/doc_test/doc_role_need_max_title_length/conf.py index 1c27fc5e7..46b0b1685 100644 --- a/tests/doc_test/doc_role_need_max_title_length/conf.py +++ b/tests/doc_test/doc_role_need_max_title_length/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -12,8 +10,3 @@ needs_role_need_template = "[{id}] {title} ({status}) {type_name}/{type} - {tags} - {links} - {links_back} - {content}" needs_role_need_max_title_length = 10 - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_role_need_max_title_length_unlimited/conf.py b/tests/doc_test/doc_role_need_max_title_length_unlimited/conf.py index a72bc09e9..23dec017c 100644 --- a/tests/doc_test/doc_role_need_max_title_length_unlimited/conf.py +++ b/tests/doc_test/doc_role_need_max_title_length_unlimited/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -12,8 +10,3 @@ needs_role_need_template = "[{id}] {title} ({status}) {type_name}/{type} - {tags} - {links} - {links_back} - {content}" needs_role_need_max_title_length = -1 - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_role_need_template/conf.py b/tests/doc_test/doc_role_need_template/conf.py index da01d5bc9..4d15bdb0d 100644 --- a/tests/doc_test/doc_role_need_template/conf.py +++ b/tests/doc_test/doc_role_need_template/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -10,8 +8,3 @@ ] needs_role_need_template = "[{id}] {title} ({status}) {type_name}/{type} - {tags} - {links} - {links_back} - {content}" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_style_blank/conf.py b/tests/doc_test/doc_style_blank/conf.py index 86cb5f045..ef8a46842 100644 --- a/tests/doc_test/doc_style_blank/conf.py +++ b/tests/doc_test/doc_style_blank/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -10,8 +8,3 @@ ] needs_css = "blank.css" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_style_custom/conf.py b/tests/doc_test/doc_style_custom/conf.py index bf781778e..80485dc17 100644 --- a/tests/doc_test/doc_style_custom/conf.py +++ b/tests/doc_test/doc_style_custom/conf.py @@ -10,8 +10,3 @@ ] needs_css = os.path.join(os.path.dirname(__file__), "my_custom.css") - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_style_modern/conf.py b/tests/doc_test/doc_style_modern/conf.py index 8552cb40d..68f00c54c 100644 --- a/tests/doc_test/doc_style_modern/conf.py +++ b/tests/doc_test/doc_style_modern/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -10,8 +8,3 @@ ] needs_css = "modern.css" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/doc_style_unknown/conf.py b/tests/doc_test/doc_style_unknown/conf.py index dc15b11c0..ec0cfafe9 100644 --- a/tests/doc_test/doc_style_unknown/conf.py +++ b/tests/doc_test/doc_style_unknown/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -10,8 +8,3 @@ ] needs_css = "UNKNOWN.css" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/external_doc/conf.py b/tests/doc_test/external_doc/conf.py index ef512823c..e38367471 100644 --- a/tests/doc_test/external_doc/conf.py +++ b/tests/doc_test/external_doc/conf.py @@ -4,6 +4,9 @@ extensions = ["sphinxcontrib.plantuml", "sphinx_needs"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_id_regex = "^[A-Za-z0-9_]" needs_types = [ @@ -25,8 +28,3 @@ # Needed to export really ALL needs. The default entry would filter out all needs coming from external needs_builder_filter = "True" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/extra_options/conf.py b/tests/doc_test/extra_options/conf.py index 6e47f549a..7518f91ca 100644 --- a/tests/doc_test/extra_options/conf.py +++ b/tests/doc_test/extra_options/conf.py @@ -1,14 +1,7 @@ -import os - from docutils.parsers.rst import directives extensions = ["sphinx_needs"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_extra_options = { "introduced": directives.unchanged, "updated": directives.unchanged, diff --git a/tests/doc_test/filter_doc/conf.py b/tests/doc_test/filter_doc/conf.py index 772b08f5a..ffcff9833 100644 --- a/tests/doc_test/filter_doc/conf.py +++ b/tests/doc_test/filter_doc/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -11,8 +9,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/generic_doc/conf.py b/tests/doc_test/generic_doc/conf.py index 7974f2989..21eab6d52 100644 --- a/tests/doc_test/generic_doc/conf.py +++ b/tests/doc_test/generic_doc/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -8,8 +6,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/import_doc/conf.py b/tests/doc_test/import_doc/conf.py index ffa0fe223..fcbde4dd9 100644 --- a/tests/doc_test/import_doc/conf.py +++ b/tests/doc_test/import_doc/conf.py @@ -1,5 +1,3 @@ -import os - version = "1.0" extensions = ["sphinx_needs"] @@ -32,8 +30,3 @@ {% endif -%} """ - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/import_doc_empty/conf.py b/tests/doc_test/import_doc_empty/conf.py index 5351ffb08..45270f660 100644 --- a/tests/doc_test/import_doc_empty/conf.py +++ b/tests/doc_test/import_doc_empty/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -30,8 +28,3 @@ {% endif -%} """ - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/import_doc_invalid/conf.py b/tests/doc_test/import_doc_invalid/conf.py index 5351ffb08..45270f660 100644 --- a/tests/doc_test/import_doc_invalid/conf.py +++ b/tests/doc_test/import_doc_invalid/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -30,8 +28,3 @@ {% endif -%} """ - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/multiple_link_backs/conf.py b/tests/doc_test/multiple_link_backs/conf.py index 8a9332c49..64873d961 100644 --- a/tests/doc_test/multiple_link_backs/conf.py +++ b/tests/doc_test/multiple_link_backs/conf.py @@ -1,8 +1 @@ -import os - extensions = ["sphinx_needs"] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/need_constraints/conf.py b/tests/doc_test/need_constraints/conf.py index acbee6adf..b33483a78 100644 --- a/tests/doc_test/need_constraints/conf.py +++ b/tests/doc_test/need_constraints/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_build_json = True @@ -12,11 +10,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ {"base_url": "http://my_company.com/docs/v1/", "json_path": "needs_test_small.json", "id_prefix": "ext_"} ] diff --git a/tests/doc_test/need_constraints_failed/conf.py b/tests/doc_test/need_constraints_failed/conf.py index e9f872cec..31228134f 100644 --- a/tests/doc_test/need_constraints_failed/conf.py +++ b/tests/doc_test/need_constraints_failed/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -11,11 +9,6 @@ {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "../need_constraints", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" - needs_external_needs = [ {"base_url": "http://my_company.com/docs/v1/", "json_path": "needs_test_small.json", "id_prefix": "ext_"} ] diff --git a/tests/doc_test/needextract_with_nested_needs/conf.py b/tests/doc_test/needextract_with_nested_needs/conf.py index 440f78616..df3fe57f8 100644 --- a/tests/doc_test/needextract_with_nested_needs/conf.py +++ b/tests/doc_test/needextract_with_nested_needs/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/needpie_with_zero_needs/conf.py b/tests/doc_test/needpie_with_zero_needs/conf.py index 440f78616..df3fe57f8 100644 --- a/tests/doc_test/needpie_with_zero_needs/conf.py +++ b/tests/doc_test/needpie_with_zero_needs/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/non_exists_file_import/conf.py b/tests/doc_test/non_exists_file_import/conf.py index 5351ffb08..45270f660 100644 --- a/tests/doc_test/non_exists_file_import/conf.py +++ b/tests/doc_test/non_exists_file_import/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_id_regex = "^[A-Za-z0-9_]" @@ -30,8 +28,3 @@ {% endif -%} """ - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/parallel_doc/conf.py b/tests/doc_test/parallel_doc/conf.py index 07468f5ae..03f708826 100644 --- a/tests/doc_test/parallel_doc/conf.py +++ b/tests/doc_test/parallel_doc/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_types = [ @@ -12,7 +10,3 @@ needs_variant_options = ["status", "author"] needs_filter_data = {"assignee": "Randy Duodu"} needs_extra_options = ["my_extra_option", "another_option", "author", "comment"] -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/role_need_doc/conf.py b/tests/doc_test/role_need_doc/conf.py index 56fbf76ab..a3d0a4e67 100644 --- a/tests/doc_test/role_need_doc/conf.py +++ b/tests/doc_test/role_need_doc/conf.py @@ -2,6 +2,9 @@ extensions = ["sphinxcontrib.plantuml", "sphinx_needs"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_id_regex = "^[A-Za-z0-9_]" needs_types = [ @@ -23,8 +26,3 @@ # Needed to export really ALL needs. The default entry would filter out all needs coming from external needs_builder_filter = "True" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/service_doc/conf.py b/tests/doc_test/service_doc/conf.py index d423705ac..b2a23705d 100644 --- a/tests/doc_test/service_doc/conf.py +++ b/tests/doc_test/service_doc/conf.py @@ -1,5 +1,3 @@ -import os - from tests.test_services.test_service_basics import NoDebugService, ServiceTest extensions = ["sphinx_needs"] @@ -27,9 +25,3 @@ }, }, } - - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/title_from_content/conf.py b/tests/doc_test/title_from_content/conf.py index 61c73ebb9..8b1a4a0c3 100644 --- a/tests/doc_test/title_from_content/conf.py +++ b/tests/doc_test/title_from_content/conf.py @@ -1,11 +1,4 @@ -import os - extensions = ["sphinx_needs"] needs_title_from_content = True needs_max_title_length = 50 smartquotes_action = "qD" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/title_optional/conf.py b/tests/doc_test/title_optional/conf.py index 275d23e75..cdc89c774 100644 --- a/tests/doc_test/title_optional/conf.py +++ b/tests/doc_test/title_optional/conf.py @@ -1,11 +1,4 @@ -import os - extensions = ["sphinx_needs"] needs_title_optional = True needs_max_title_length = 50 smartquotes_action = "qD" - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/unicode_support/conf.py b/tests/doc_test/unicode_support/conf.py index 6c0a46f6b..885bd47d6 100644 --- a/tests/doc_test/unicode_support/conf.py +++ b/tests/doc_test/unicode_support/conf.py @@ -1,5 +1,3 @@ -import os - extensions = ["sphinx_needs"] needs_table_style = "TABLE" @@ -10,8 +8,3 @@ {"directive": "impl", "title": "Implementation", "prefix": "IM_", "color": "#DF744A", "style": "node"}, {"directive": "test", "title": "Test Case", "prefix": "TC_", "color": "#DCB239", "style": "node"}, ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/variant_doc/conf.py b/tests/doc_test/variant_doc/conf.py index 85c4de687..d94dd50ed 100644 --- a/tests/doc_test/variant_doc/conf.py +++ b/tests/doc_test/variant_doc/conf.py @@ -1,9 +1,10 @@ -import os - tags.add("tag_b") # noqa: F821 extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_id_regex = "^[A-Za-z0-9_]" needs_types = [ @@ -28,9 +29,3 @@ "value", "unit", ] - - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/doc_test/variant_doc/index.rst b/tests/doc_test/variant_doc/index.rst index 81983e196..e18c1341c 100644 --- a/tests/doc_test/variant_doc/index.rst +++ b/tests/doc_test/variant_doc/index.rst @@ -34,11 +34,3 @@ Variant Handling Test .. toctree:: :maxdepth: 2 :caption: Contents: - - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`modindex` -* :ref:`search` diff --git a/tests/doc_test/variant_options/conf.py b/tests/doc_test/variant_options/conf.py index 44943a950..42108d4a1 100644 --- a/tests/doc_test/variant_options/conf.py +++ b/tests/doc_test/variant_options/conf.py @@ -1,9 +1,10 @@ -import os - tags.add("tag_b") # noqa: F821 extensions = ["sphinx_needs", "sphinxcontrib.plantuml"] +# note, the plantuml executable command is set globally in the test suite +plantuml_output_format = "svg" + needs_id_regex = "^[A-Za-z0-9_]" needs_types = [ @@ -28,8 +29,3 @@ "value", "unit", ] - -plantuml = "java -Djava.awt.headless=true -jar %s" % os.path.join( - os.path.dirname(__file__), "..", "utils", "plantuml.jar" -) -plantuml_output_format = "svg" diff --git a/tests/js_test/sn-collapse-button.cy.js b/tests/js_test/sn-collapse-button.cy.js new file mode 100644 index 000000000..93131f9e6 --- /dev/null +++ b/tests/js_test/sn-collapse-button.cy.js @@ -0,0 +1,86 @@ +describe('Test Sphinx Needs Collapse', () => { + it('Visit Sphinx Needs Homepage', () => { + // 1. Given a user visits http://localhost:65323/ + cy.visit('/') + + cy.get('table.need span.needs.needs_collapse').each(($el, index, $list) => { + // 2. When page loads, select all elements that matches the selector `table.need span.needs.needs_collapse` + + var id = $el.attr("id"); + var parts = id.split("__"); + var rows = parts.slice(2); + + var table = $el.closest('table'); + var need_table_id = table.closest("div[id^=SNCB-]").attr("id"); + + // 3. Check if the id of the element contains show or hide + if (parts[1] == "show") { + cy.get($el).within(() => { + // 4. Then check if `span.needs.visible` has the class `collapse_is_hidden` + cy.get('span.needs.visible').should('have.class', 'collapse_is_hidden') + }) + } else { + cy.get($el).within(() => { + // 4. Then check if `span.needs.collapse` has the class `collapse_is_hidden` + cy.get('span.needs.collapsed').should('have.class', 'collapse_is_hidden') + }) + + for (var row in rows) { + // 5. And check if `#${need_table_id} table tr.${rows[row]}` has the class `collapse_is_hidden` + cy.get(`#${need_table_id} table tr.${rows[row]}`).should('have.class', 'collapse_is_hidden') + } + } + }) + }) +}) + +describe('Test Sphinx Needs Collapse Click', () => { + it('Visit Sphinx Needs Directive page', () => { + // 1. Given a user visits http://localhost:65323/ + cy.visit('/') + + cy.get('table.need span.needs.needs_collapse').each(($el, index, $list) => { + // 2. When page loads, select all elements that matches the selector `table.need span.needs.needs_collapse` + + var id = $el.attr("id"); + var parts = id.split("__"); + var rows = parts.slice(2); + + var table = $el.closest('table'); + var need_table_id = table.closest("div[id^=SNCB-]").attr("id"); + + if (parts[1] == "show") { + // 3. Click collapse/expand button + cy.get($el).click() + + for (var row in rows) { + // 4. And check if `#${need_table_id} table tr.${rows[row]}` has the class `collapse_is_hidden` + cy.get(`#${need_table_id} table tr.${rows[row]}`).should('have.class', 'collapse_is_hidden') + } + + cy.get($el).within(() => { + // 5. Then check if `span.needs.collapse` has the class `collapse_is_hidden` + cy.get('span.needs.collapsed').should('have.class', 'collapse_is_hidden') + // 6. And check if `span.needs.visible` has the class `collapse_is_hidden` + cy.get('span.needs.visible').should('not.have.class', 'collapse_is_hidden') + }) + } else{ + // 3. Click collapse/expand button + cy.get($el).click() + + for (var row in rows) { + // 4. And check if `#${need_table_id} table tr.${rows[row]}` has the class `collapse_is_hidden` + cy.get(`#${need_table_id} table tr.${rows[row]}`).should('not.have.class', 'collapse_is_hidden') + } + + cy.get($el).within(() => { + // 5. Then check if `span.needs.collapse` has the class `collapse_is_hidden` + cy.get('span.needs.collapsed').should('not.have.class', 'collapse_is_hidden') + // 6. Check if `span.needs.visible` has the class `collapse_is_hidden` + cy.get('span.needs.visible').should('have.class', 'collapse_is_hidden') + }) + } + + }) + }) +}) \ No newline at end of file diff --git a/tests/test_layouts.py b/tests/test_layouts.py index e20aca3f7..e886c2fbd 100644 --- a/tests/test_layouts.py +++ b/tests/test_layouts.py @@ -23,8 +23,11 @@ def test_doc_build_html(test_app): assert "title_example_layout" in html needs = extract_needs_from_html(html) - assert len(needs) == 5 + assert len(needs) == 6 + assert ( + 'author: some author' in html + ) assert '' in html # check simple_footer grid layout diff --git a/tests/test_needextend.py b/tests/test_needextend.py index 0751f87d0..c4095446f 100644 --- a/tests/test_needextend.py +++ b/tests/test_needextend.py @@ -64,3 +64,17 @@ def test_doc_needextend_strict(test_app): "Sphinx error:\nProvided id strict_enable_extend_test for needextend does not exist." in out.stderr.decode("utf-8") ) + + +@pytest.mark.parametrize( + "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needextend_dynamic"}], indirect=True +) +def test_doc_needextend_dynamic(test_app, snapshot): + app = test_app + app.build() + + # for some reason this intermittently creates incorrect warnings about overriding visitors + # assert app._warning.getvalue() == "" + + needs_data = json.loads(Path(app.outdir, "needs.json").read_text()) + assert needs_data == snapshot(exclude=props("created")) diff --git a/tests/test_needs_external_needs_build.py b/tests/test_needs_external_needs_build.py index 4dfc21878..0a3c8876b 100644 --- a/tests/test_needs_external_needs_build.py +++ b/tests/test_needs_external_needs_build.py @@ -1,3 +1,4 @@ +import os import sys from pathlib import Path @@ -10,26 +11,29 @@ @pytest.mark.parametrize( "test_app", [{"buildername": "html", "srcdir": "doc_test/doc_needs_external_needs"}], indirect=True ) -def test_doc_build_html(test_app): +def test_doc_build_html(test_app, sphinx_test_tempdir): import subprocess app = test_app src_dir = Path(app.srcdir) out_dir = Path(app.outdir) - output = subprocess.run(["sphinx-build", "-M", "html", src_dir, out_dir], capture_output=True) - assert not output.stderr, f"Should not have stderr: {output.stderr}" + plantuml = r"java -Djava.awt.headless=true -jar %s" % os.path.join(sphinx_test_tempdir, "utils", "plantuml.jar") + output = subprocess.run( + ["sphinx-build", "-b", "html", "-D", rf"plantuml={plantuml}", src_dir, out_dir], capture_output=True + ) + assert not output.stderr, f"Build failed with stderr: {output.stderr}" # run second time and check - output_second = subprocess.run(["sphinx-build", "-M", "html", src_dir, out_dir], capture_output=True) + output_second = subprocess.run( + ["sphinx-build", "-b", "html", "-D", rf"plantuml={plantuml}", src_dir, out_dir], capture_output=True + ) assert not output_second.stderr # check if incremental build used # first build output - assert "making output directory" in output.stdout.decode("utf-8") assert "updating environment: [new config] 3 added, 0 changed, 0 removed" in output.stdout.decode("utf-8") # second build output - assert "making output directory" not in output_second.stdout.decode("utf-8") assert "loading pickled environment" in output_second.stdout.decode("utf-8") assert "updating environment: [new config] 3 added, 0 changed, 0 removed" not in output_second.stdout.decode( "utf-8" diff --git a/tests/test_needs_id_builder.py b/tests/test_needs_id_builder.py index cbf86ad46..6c647242b 100644 --- a/tests/test_needs_id_builder.py +++ b/tests/test_needs_id_builder.py @@ -1,8 +1,8 @@ import json -import os from pathlib import Path import pytest +from syrupy.filters import props from sphinx_needs.config import NeedsSphinxConfig from sphinx_needs.data import SphinxNeedsData @@ -11,23 +11,11 @@ @pytest.mark.parametrize( "test_app", [{"buildername": "needs_id", "srcdir": "doc_test/doc_needs_builder"}], indirect=True ) -def test_doc_needs_id_builder(test_app): +def test_doc_needs_id_builder(test_app, snapshot): 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"] + data = SphinxNeedsData(app.env) + needs_config = NeedsSphinxConfig(app.config) + needs_id_path = Path(app.outdir, needs_config.build_json_per_id_path) + data = {path.name: json.loads(path.read_text()) for path in needs_id_path.glob("*.json")} + assert data == snapshot(exclude=props("created")) diff --git a/tests/test_sn_collapse_button.py b/tests/test_sn_collapse_button.py new file mode 100644 index 000000000..1aa37a23f --- /dev/null +++ b/tests/test_sn_collapse_button.py @@ -0,0 +1,52 @@ +import pytest + + +@pytest.mark.jstest +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/variant_doc", + "tags": ["tag_a"], + "spec_pattern": "js_test/sn-collapse-button.cy.js", + } + ], + indirect=True, +) +def test_collapse_button_in_variant_doc(test_app, test_server): + """Check if the Sphinx-Needs collapse button works in the provided documentation source.""" + app = test_app + app.build() + + # Call `app.test_js()` to run the JS test for a particular specPattern + js_test_result = app.test_js() + + # Check the return code and stdout + assert js_test_result["returncode"] == 0 + assert "All specs passed!" in js_test_result["stdout"].decode("utf-8") + + +@pytest.mark.jstest +@pytest.mark.parametrize( + "test_app", + [ + { + "buildername": "html", + "srcdir": "doc_test/doc_basic", + "spec_pattern": "js_test/sn-collapse-button.cy.js", + } + ], + indirect=True, +) +def test_collapse_button_in_doc_basic(test_app, test_server): + """Check if the Sphinx-Needs collapse button works in the provided documentation source.""" + app = test_app + app.build() + + # Call `app.test_js()` to run the JS test for a particular specPattern + js_test_result = app.test_js() + + # Check the return code and stdout + assert js_test_result["returncode"] == 0 + assert "All specs passed!" in js_test_result["stdout"].decode("utf-8")