diff --git a/.dockerignore b/.dockerignore index c2e9e8e84..9d9f68fbe 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,5 +1,6 @@ .tox .venv +.venv39 .mypy_cache .pytest_cache .git diff --git a/.github/workflows/validate.yaml b/.github/workflows/validate.yaml index b4318a959..f797c3247 100644 --- a/.github/workflows/validate.yaml +++ b/.github/workflows/validate.yaml @@ -25,26 +25,26 @@ jobs: strategy: fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12"] os: [ubuntu-latest, macos-latest, windows-latest] # This is used for injecting additional tests for a specific python # version and OS. suffix: [""] include: - - python-version: "3.8" + - python-version: "3.9" os: ubuntu-latest extensive-tests: true TOXENV_SUFFIX: "-docs" - - python-version: "3.8" + - python-version: "3.9" os: ubuntu-latest extensive-tests: true PREPARATION: "sudo apt-get install -y libxml2-dev libxslt-dev" suffix: "-min" TOXENV_SUFFIX: "-min" - - python-version: "3.9" + - python-version: "3.10" os: ubuntu-latest TOXENV_SUFFIX: "-docs" - - python-version: "3.10" + - python-version: "3.11" os: ubuntu-latest TOX_EXTRA_COMMAND: "- black --check --diff ./rdflib" TOXENV_SUFFIX: "-lxml" @@ -55,6 +55,10 @@ jobs: extensive-tests: true TOX_TEST_HARNESS: "firejail --net=none --" TOX_PYTEST_EXTRA_ARGS: "-m 'not webtest'" + - python-version: "3.12" + os: ubuntu-latest + TOX_EXTRA_COMMAND: "- black --check --diff ./rdflib" + TOXENV_SUFFIX: "-lxml" steps: - uses: actions/checkout@v4 - name: Cache XDG_CACHE_HOME @@ -121,7 +125,7 @@ jobs: matrix: include: - task: "gha:lint" - python-version: 3.8 + python-version: 3.9 steps: - uses: actions/checkout@v4 - name: Cache XDG_CACHE_HOME diff --git a/.gitignore b/.gitignore index d42dc26fd..1a822fd6c 100644 --- a/.gitignore +++ b/.gitignore @@ -139,6 +139,7 @@ celerybeat.pid # Environments .env .venv +.venv39 env/ venv/ ENV/ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8a74122cc..58cdd2e50 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,20 +8,20 @@ ci: repos: - repo: https://github.com/astral-sh/ruff-pre-commit # WARNING: Ruff version should be the same as in `pyproject.toml` - rev: v0.5.4 + rev: v0.7.1 hooks: - id: ruff args: ["--fix"] - repo: https://github.com/psf/black-pre-commit-mirror # WARNING: Black version should be the same as in `pyproject.toml` - rev: "24.4.2" + rev: "24.10.0" hooks: - id: black pass_filenames: false require_serial: true args: ["."] - repo: https://github.com/python-poetry/poetry - rev: 1.8.3 + rev: 1.8.4 hooks: - id: poetry-check - id: poetry-lock diff --git a/devtools/constraints.min b/devtools/constraints.min index c4f677af6..ccb2ec5b3 100644 --- a/devtools/constraints.min +++ b/devtools/constraints.min @@ -2,10 +2,11 @@ # these versions. The file's extension (`.min`) is chosen to evade Dependabot # which operates on `*.{txt,in}` files. isodate==0.7.2; python_version < "3.11" -pyparsing==2.1.0 +pyparsing==3.2.0 importlib-metadata==4.0.0 berkeleydb==18.1.2 networkx==2.0 html5rdf==1.2.1 -lxml==4.3.0 +lxml==4.8.0; python_version < "3.11" +lxml==4.9.3; python_version >= "3.11" orjson==3.9.14 diff --git a/devtools/diffrtpy.py b/devtools/diffrtpy.py index 1d4b09722..934550bb3 100755 --- a/devtools/diffrtpy.py +++ b/devtools/diffrtpy.py @@ -26,7 +26,6 @@ from dataclasses import dataclass, field from difflib import unified_diff from pathlib import Path -from typing import List import black import python_minifier @@ -79,7 +78,7 @@ def __post_init__(self) -> None: parser.add_argument("rhs_file", nargs=1, type=str) parser.set_defaults(handler=self.handle) - def run(self, args: List[str]) -> None: + def run(self, args: list[str]) -> None: parse_result = self.parser.parse_args(args) verbosity = parse_result.verbosity diff --git a/docker/latest/requirements.txt b/docker/latest/requirements.txt index c0842001b..8fb79d415 100644 --- a/docker/latest/requirements.txt +++ b/docker/latest/requirements.txt @@ -6,7 +6,7 @@ # html5rdf==1.2.1 # via -r docker/latest/requirements.in -pyparsing==3.0.9 +pyparsing==3.2.0 # via rdflib rdflib==7.1.1 # via -r docker/latest/requirements.in diff --git a/docs/conf.py b/docs/conf.py index 44b21a91b..4aba4664f 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -15,7 +15,7 @@ import os import re import sys -from typing import Any, Dict +from typing import Any import sphinx import sphinx.application @@ -87,19 +87,6 @@ # |version| and |release|, also used in various other places throughout the # built documents. - -# Find version. We have to do this because we can't import it in Python 3 until -# its been automatically converted in the setup process. -# UPDATE: This function is no longer used; once builds are confirmed to succeed, it -# can/should be removed. --JCL 2022-12-30 -def find_version(filename): - _version_re = re.compile(r'__version__ = "(.*)"') - for line in open(filename): - version_match = _version_re.match(line) - if version_match: - return version_match.group(1) - - # The full version, including alpha/beta/rc tags. release = rdflib.__version__ # The short X.Y version. @@ -255,7 +242,7 @@ def find_version(filename): # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { - "python": ("https://docs.python.org/3.8", None), + "python": ("https://docs.python.org/3.9", None), } html_experimental_html5_writer = True @@ -283,6 +270,8 @@ def find_version(filename): ("py:class", "pyparsing.core.TokenConverter"), ("py:class", "pyparsing.results.ParseResults"), ("py:class", "pyparsing.core.ParserElement"), + ("py:class", "re.Pattern"), + ("py:class", "re.Match"), ] @@ -292,7 +281,7 @@ def autodoc_skip_member_handler( name: str, obj: Any, skip: bool, - options: Dict[str, Any], + options: dict[str, Any], ): """ This function will be called by Sphinx when it is deciding whether to skip a diff --git a/docs/developers.rst b/docs/developers.rst index 7ca914fca..4a9e2266b 100644 --- a/docs/developers.rst +++ b/docs/developers.rst @@ -313,13 +313,13 @@ makes it easier to run validation on all supported python versions. tox -a # Run a specific environment. - tox -e py38 # default environment with py37 - tox -e py39-extra # extra tests with py39 + tox -e py39 # default environment with py39 + tox -e py311-extra # extra tests with py311 # Override the test command. # the below command will run `pytest test/test_translate_algebra.py` # instead of the default pytest command. - tox -e py38,py39 -- pytest test/test_translate_algebra.py + tox -e py39,py311 -- pytest test/test_translate_algebra.py ``go-task`` and ``Taskfile.yml`` diff --git a/docs/type_hints.rst b/docs/type_hints.rst index 31eed6ee7..7d5bf5028 100644 --- a/docs/type_hints.rst +++ b/docs/type_hints.rst @@ -50,7 +50,7 @@ The following is an example of a type alias ``Bar``: from typing import Tuple - Bar = Tuple[int, str] + Bar = tuple[int, str] RDFLib will provide public type aliases under the ``rdflib.typing`` package, for example, ``rdflib.typing.Triple``, ``rdflib.typing.Quad``. Type aliases in the rest of RDFLib should be private (i.e. being with an underscore). diff --git a/examples/secure_with_audit.py b/examples/secure_with_audit.py index 2bd4e28fb..7df044cad 100644 --- a/examples/secure_with_audit.py +++ b/examples/secure_with_audit.py @@ -15,12 +15,12 @@ import logging import os import sys -from typing import Any, Optional, Tuple +from typing import Any, Optional from rdflib import Graph -def audit_hook(name: str, args: Tuple[Any, ...]) -> None: +def audit_hook(name: str, args: tuple[Any, ...]) -> None: """ An audit hook that blocks access when an attempt is made to open a file or URL that ends with ``blocked.jsonld``. diff --git a/poetry.lock b/poetry.lock index c8bea115f..b65850bb2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,69 +1,69 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] name = "babel" -version = "2.12.1" +version = "2.16.0" description = "Internationalization utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" 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.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] -[package.dependencies] -pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "berkeleydb" -version = "18.1.10" +version = "18.1.11" description = "Python bindings for Oracle Berkeley DB" optional = true python-versions = "*" files = [ - {file = "berkeleydb-18.1.10.tar.gz", hash = "sha256:426341a16007a9002d987a6f4d97226f8eafffcb1a0488488053d38a3127c81a"}, + {file = "berkeleydb-18.1.11.tar.gz", hash = "sha256:7454f560d2d1a0e5d0d5630a437f19926b68bc794eb161edea2cdc4b267cf574"}, ] [[package]] name = "black" -version = "24.4.2" +version = "24.10.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"}, - {file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"}, - {file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"}, - {file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"}, - {file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"}, - {file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"}, - {file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"}, - {file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"}, - {file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"}, - {file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"}, - {file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"}, - {file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"}, - {file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"}, - {file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"}, - {file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"}, - {file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"}, - {file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"}, - {file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"}, - {file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"}, - {file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"}, - {file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"}, - {file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"}, + {file = "black-24.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e6668650ea4b685440857138e5fe40cde4d652633b1bdffc62933d0db4ed9812"}, + {file = "black-24.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:1c536fcf674217e87b8cc3657b81809d3c085d7bf3ef262ead700da345bfa6ea"}, + {file = "black-24.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:649fff99a20bd06c6f727d2a27f401331dc0cc861fb69cde910fe95b01b5928f"}, + {file = "black-24.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:fe4d6476887de70546212c99ac9bd803d90b42fc4767f058a0baa895013fbb3e"}, + {file = "black-24.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5a2221696a8224e335c28816a9d331a6c2ae15a2ee34ec857dcf3e45dbfa99ad"}, + {file = "black-24.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f9da3333530dbcecc1be13e69c250ed8dfa67f43c4005fb537bb426e19200d50"}, + {file = "black-24.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4007b1393d902b48b36958a216c20c4482f601569d19ed1df294a496eb366392"}, + {file = "black-24.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:394d4ddc64782e51153eadcaaca95144ac4c35e27ef9b0a42e121ae7e57a9175"}, + {file = "black-24.10.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b5e39e0fae001df40f95bd8cc36b9165c5e2ea88900167bddf258bacef9bbdc3"}, + {file = "black-24.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d37d422772111794b26757c5b55a3eade028aa3fde43121ab7b673d050949d65"}, + {file = "black-24.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:14b3502784f09ce2443830e3133dacf2c0110d45191ed470ecb04d0f5f6fcb0f"}, + {file = "black-24.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:30d2c30dc5139211dda799758559d1b049f7f14c580c409d6ad925b74a4208a8"}, + {file = "black-24.10.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1cbacacb19e922a1d75ef2b6ccaefcd6e93a2c05ede32f06a21386a04cedb981"}, + {file = "black-24.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1f93102e0c5bb3907451063e08b9876dbeac810e7da5a8bfb7aeb5a9ef89066b"}, + {file = "black-24.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ddacb691cdcdf77b96f549cf9591701d8db36b2f19519373d60d31746068dbf2"}, + {file = "black-24.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:680359d932801c76d2e9c9068d05c6b107f2584b2a5b88831c83962eb9984c1b"}, + {file = "black-24.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:17374989640fbca88b6a448129cd1745c5eb8d9547b464f281b251dd00155ccd"}, + {file = "black-24.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:63f626344343083322233f175aaf372d326de8436f5928c042639a4afbbf1d3f"}, + {file = "black-24.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfa1d0cb6200857f1923b602f978386a3a2758a65b52e0950299ea014be6800"}, + {file = "black-24.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:2cd9c95431d94adc56600710f8813ee27eea544dd118d45896bb734e9d7a0dc7"}, + {file = "black-24.10.0-py3-none-any.whl", hash = "sha256:3bb2b7a1f7b685f85b11fed1ef10f8a9148bceb49853e47a294a3dd963c1dd7d"}, + {file = "black-24.10.0.tar.gz", hash = "sha256:846ea64c97afe3bc677b761787993be4991810ecc7a4a937816dd6bddedc4875"}, ] [package.dependencies] @@ -77,7 +77,7 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] @@ -108,97 +108,127 @@ virtualenv = ["virtualenv (>=20.0.35)"] [[package]] name = "certifi" -version = "2023.7.22" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.7.22-py3-none-any.whl", hash = "sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9"}, - {file = "certifi-2023.7.22.tar.gz", hash = "sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] name = "charset-normalizer" -version = "3.2.0" +version = "3.4.0" 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.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -228,83 +258,73 @@ files = [ [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.4" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5f8ae553cba74085db385d489c7a792ad66f7f9ba2ee85bfa508aeb84cf0ba07"}, + {file = "coverage-7.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8165b796df0bd42e10527a3f493c592ba494f16ef3c8b531288e3d0d72c1f6f0"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c7c8b95bf47db6d19096a5e052ffca0a05f335bc63cef281a6e8fe864d450a72"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ed9281d1b52628e81393f5eaee24a45cbd64965f41857559c2b7ff19385df51"}, + {file = "coverage-7.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0809082ee480bb8f7416507538243c8863ac74fd8a5d2485c46f0f7499f2b491"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d541423cdd416b78626b55f123412fcf979d22a2c39fce251b350de38c15c15b"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:58809e238a8a12a625c70450b48e8767cff9eb67c62e6154a642b21ddf79baea"}, + {file = "coverage-7.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c9b8e184898ed014884ca84c70562b4a82cbc63b044d366fedc68bc2b2f3394a"}, + {file = "coverage-7.6.4-cp310-cp310-win32.whl", hash = "sha256:6bd818b7ea14bc6e1f06e241e8234508b21edf1b242d49831831a9450e2f35fa"}, + {file = "coverage-7.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:06babbb8f4e74b063dbaeb74ad68dfce9186c595a15f11f5d5683f748fa1d172"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:73d2b73584446e66ee633eaad1a56aad577c077f46c35ca3283cd687b7715b0b"}, + {file = "coverage-7.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:51b44306032045b383a7a8a2c13878de375117946d68dcb54308111f39775a25"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3fb02fe73bed561fa12d279a417b432e5b50fe03e8d663d61b3d5990f29546"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ed8fe9189d2beb6edc14d3ad19800626e1d9f2d975e436f84e19efb7fa19469b"}, + {file = "coverage-7.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b369ead6527d025a0fe7bd3864e46dbee3aa8f652d48df6174f8d0bac9e26e0e"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ade3ca1e5f0ff46b678b66201f7ff477e8fa11fb537f3b55c3f0568fbfe6e718"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:27fb4a050aaf18772db513091c9c13f6cb94ed40eacdef8dad8411d92d9992db"}, + {file = "coverage-7.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4f704f0998911abf728a7783799444fcbbe8261c4a6c166f667937ae6a8aa522"}, + {file = "coverage-7.6.4-cp311-cp311-win32.whl", hash = "sha256:29155cd511ee058e260db648b6182c419422a0d2e9a4fa44501898cf918866cf"}, + {file = "coverage-7.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:8902dd6a30173d4ef09954bfcb24b5d7b5190cf14a43170e386979651e09ba19"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:12394842a3a8affa3ba62b0d4ab7e9e210c5e366fbac3e8b2a68636fb19892c2"}, + {file = "coverage-7.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b6b4c83d8e8ea79f27ab80778c19bc037759aea298da4b56621f4474ffeb117"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d5b8007f81b88696d06f7df0cb9af0d3b835fe0c8dbf489bad70b45f0e45613"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b57b768feb866f44eeed9f46975f3d6406380275c5ddfe22f531a2bf187eda27"}, + {file = "coverage-7.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5915fcdec0e54ee229926868e9b08586376cae1f5faa9bbaf8faf3561b393d52"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:0b58c672d14f16ed92a48db984612f5ce3836ae7d72cdd161001cc54512571f2"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2fdef0d83a2d08d69b1f2210a93c416d54e14d9eb398f6ab2f0a209433db19e1"}, + {file = "coverage-7.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cf717ee42012be8c0cb205dbbf18ffa9003c4cbf4ad078db47b95e10748eec5"}, + {file = "coverage-7.6.4-cp312-cp312-win32.whl", hash = "sha256:7bb92c539a624cf86296dd0c68cd5cc286c9eef2d0c3b8b192b604ce9de20a17"}, + {file = "coverage-7.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:1032e178b76a4e2b5b32e19d0fd0abbce4b58e77a1ca695820d10e491fa32b08"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:023bf8ee3ec6d35af9c1c6ccc1d18fa69afa1cb29eaac57cb064dbb262a517f9"}, + {file = "coverage-7.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b0ac3d42cb51c4b12df9c5f0dd2f13a4f24f01943627120ec4d293c9181219ba"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8fe4984b431f8621ca53d9380901f62bfb54ff759a1348cd140490ada7b693c"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5fbd612f8a091954a0c8dd4c0b571b973487277d26476f8480bfa4b2a65b5d06"}, + {file = "coverage-7.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dacbc52de979f2823a819571f2e3a350a7e36b8cb7484cdb1e289bceaf35305f"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dab4d16dfef34b185032580e2f2f89253d302facba093d5fa9dbe04f569c4f4b"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:862264b12ebb65ad8d863d51f17758b1684560b66ab02770d4f0baf2ff75da21"}, + {file = "coverage-7.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5beb1ee382ad32afe424097de57134175fea3faf847b9af002cc7895be4e2a5a"}, + {file = "coverage-7.6.4-cp313-cp313-win32.whl", hash = "sha256:bf20494da9653f6410213424f5f8ad0ed885e01f7e8e59811f572bdb20b8972e"}, + {file = "coverage-7.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:182e6cd5c040cec0a1c8d415a87b67ed01193ed9ad458ee427741c7d8513d963"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:a181e99301a0ae128493a24cfe5cfb5b488c4e0bf2f8702091473d033494d04f"}, + {file = "coverage-7.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:df57bdbeffe694e7842092c5e2e0bc80fff7f43379d465f932ef36f027179806"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bcd1069e710600e8e4cf27f65c90c7843fa8edfb4520fb0ccb88894cad08b11"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99b41d18e6b2a48ba949418db48159d7a2e81c5cc290fc934b7d2380515bd0e3"}, + {file = "coverage-7.6.4-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6b1e54712ba3474f34b7ef7a41e65bd9037ad47916ccb1cc78769bae324c01a"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:53d202fd109416ce011578f321460795abfe10bb901b883cafd9b3ef851bacfc"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:c48167910a8f644671de9f2083a23630fbf7a1cb70ce939440cd3328e0919f70"}, + {file = "coverage-7.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc8ff50b50ce532de2fa7a7daae9dd12f0a699bfcd47f20945364e5c31799fef"}, + {file = "coverage-7.6.4-cp313-cp313t-win32.whl", hash = "sha256:b8d3a03d9bfcaf5b0141d07a88456bb6a4c3ce55c080712fec8418ef3610230e"}, + {file = "coverage-7.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:f3ddf056d3ebcf6ce47bdaf56142af51bb7fad09e4af310241e9db7a3a8022e1"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9cb7fa111d21a6b55cbf633039f7bc2749e74932e3aa7cb7333f675a58a58bf3"}, + {file = "coverage-7.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:11a223a14e91a4693d2d0755c7a043db43d96a7450b4f356d506c2562c48642c"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a413a096c4cbac202433c850ee43fa326d2e871b24554da8327b01632673a076"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00a1d69c112ff5149cabe60d2e2ee948752c975d95f1e1096742e6077affd376"}, + {file = "coverage-7.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f76846299ba5c54d12c91d776d9605ae33f8ae2b9d1d3c3703cf2db1a67f2c0"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fe439416eb6380de434886b00c859304338f8b19f6f54811984f3420a2e03858"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:0294ca37f1ba500667b1aef631e48d875ced93ad5e06fa665a3295bdd1d95111"}, + {file = "coverage-7.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6f01ba56b1c0e9d149f9ac85a2f999724895229eb36bd997b61e62999e9b0901"}, + {file = "coverage-7.6.4-cp39-cp39-win32.whl", hash = "sha256:bc66f0bf1d7730a17430a50163bb264ba9ded56739112368ba985ddaa9c3bd09"}, + {file = "coverage-7.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:c481b47f6b5845064c65a7bc78bc0860e635a9b055af0df46fdf1c58cebf8e8f"}, + {file = "coverage-7.6.4-pp39.pp310-none-any.whl", hash = "sha256:3c65d37f3a9ebb703e710befdc489a38683a5b152242664b973a7b7b22348a4e"}, + {file = "coverage-7.6.4.tar.gz", hash = "sha256:29fc0f17b1d3fea332f8001d4558f8214af7f1d87a345f3a133c901d60347c73"}, ] [package.dependencies] @@ -315,24 +335,24 @@ toml = ["tomli"] [[package]] name = "docutils" -version = "0.20.1" +version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, - {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, ] [[package]] name = "exceptiongroup" -version = "1.1.3" +version = "1.2.2" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" files = [ - {file = "exceptiongroup-1.1.3-py3-none-any.whl", hash = "sha256:343280667a4585d195ca1cf9cef84a4e178c4b6cf2274caef9859782b567d5e3"}, - {file = "exceptiongroup-1.1.3.tar.gz", hash = "sha256:097acd85d473d75af5bb98e41b61ff7fe35efe6675e4f9370ec6ec5126d160e9"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -351,15 +371,18 @@ files = [ [[package]] name = "idna" -version = "3.4" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, - {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -373,22 +396,26 @@ files = [ [[package]] name = "importlib-metadata" -version = "6.8.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-6.8.0-py3-none-any.whl", hash = "sha256:3ebb78df84a805d7698245025b975d9d67053cd94c79245ba4b3eb694abe68bb"}, - {file = "importlib_metadata-6.8.0.tar.gz", hash = "sha256:dbace7892d8c0c4ac1ad096662232f831d4e64f4c4545bd53016a3e9d4654743"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -414,13 +441,13 @@ files = [ [[package]] name = "jinja2" -version = "3.1.2" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"}, - {file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -623,82 +650,83 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.3" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cd0f502fe016460680cd20aaa5a76d241d6f35a1c3350c474bac1273803893fa"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e09031c87a1e51556fdcb46e5bd4f59dfb743061cf93c4d6831bf894f125eb57"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68e78619a61ecf91e76aa3e6e8e33fc4894a2bebe93410754bd28fce0a8a4f9f"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65c1a9bcdadc6c28eecee2c119465aebff8f7a584dd719facdd9e825ec61ab52"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:525808b8019e36eb524b8c68acdd63a37e75714eac50e988180b169d64480a00"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:962f82a3086483f5e5f64dbad880d31038b698494799b097bc59c2edf392fce6"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:aa7bd130efab1c280bed0f45501b7c8795f9fdbeb02e965371bbef3523627779"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:c9c804664ebe8f83a211cace637506669e7890fec1b4195b505c214e50dd4eb7"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win32.whl", hash = "sha256:10bbfe99883db80bdbaff2dcf681dfc6533a614f700da1287707e8a5d78a8431"}, - {file = "MarkupSafe-2.1.3-cp310-cp310-win_amd64.whl", hash = "sha256:1577735524cdad32f9f694208aa75e422adba74f1baee7551620e43a3141f559"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ad9e82fb8f09ade1c3e1b996a6337afac2b8b9e365f926f5a61aacc71adc5b3c"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3c0fae6c3be832a0a0473ac912810b2877c8cb9d76ca48de1ed31e1c68386575"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b076b6226fb84157e3f7c971a47ff3a679d837cf338547532ab866c57930dbee"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfce63a9e7834b12b87c64d6b155fdd9b3b96191b6bd334bf37db7ff1fe457f2"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:338ae27d6b8745585f87218a3f23f1512dbf52c26c28e322dbe54bcede54ccb9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e4dd52d80b8c83fdce44e12478ad2e85c64ea965e75d66dbeafb0a3e77308fcc"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:df0be2b576a7abbf737b1575f048c23fb1d769f267ec4358296f31c2479db8f9"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5bbe06f8eeafd38e5d0a4894ffec89378b6c6a625ff57e3028921f8ff59318ac"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win32.whl", hash = "sha256:dd15ff04ffd7e05ffcb7fe79f1b98041b8ea30ae9234aed2a9168b5797c3effb"}, - {file = "MarkupSafe-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:134da1eca9ec0ae528110ccc9e48041e0828d79f24121a1a146161103c76e686"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:f698de3fd0c4e6972b92290a45bd9b1536bffe8c6759c62471efaa8acb4c37bc"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:aa57bd9cf8ae831a362185ee444e15a93ecb2e344c8e52e4d721ea3ab6ef1823"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffcc3f7c66b5f5b7931a5aa68fc9cecc51e685ef90282f4a82f0f5e9b704ad11"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47d4f1c5f80fc62fdd7777d0d40a2e9dda0a05883ab11374334f6c4de38adffd"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f67c7038d560d92149c060157d623c542173016c4babc0c1913cca0564b9939"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9aad3c1755095ce347e26488214ef77e0485a3c34a50c5a5e2471dff60b9dd9c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:14ff806850827afd6b07a5f32bd917fb7f45b046ba40c57abdb636674a8b559c"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8f9293864fe09b8149f0cc42ce56e3f0e54de883a9de90cd427f191c346eb2e1"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win32.whl", hash = "sha256:715d3562f79d540f251b99ebd6d8baa547118974341db04f5ad06d5ea3eb8007"}, - {file = "MarkupSafe-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:1b8dd8c3fd14349433c79fa8abeb573a55fc0fdd769133baac1f5e07abf54aeb"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, - {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, - {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, - {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, - {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] name = "mdit-py-plugins" -version = "0.4.0" +version = "0.4.2" description = "Collection of plugins for markdown-it-py" optional = false python-versions = ">=3.8" files = [ - {file = "mdit_py_plugins-0.4.0-py3-none-any.whl", hash = "sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9"}, - {file = "mdit_py_plugins-0.4.0.tar.gz", hash = "sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b"}, + {file = "mdit_py_plugins-0.4.2-py3-none-any.whl", hash = "sha256:0c673c3f889399a33b95e88d2f0d111b4447bdfea7f237dab2d488f459835636"}, + {file = "mdit_py_plugins-0.4.2.tar.gz", hash = "sha256:5f2cd1fdb606ddf152d37ec30e46101a60512bc0e5fa1a7002c36647b09e26b5"}, ] [package.dependencies] @@ -722,38 +750,43 @@ files = [ [[package]] name = "mypy" -version = "1.11.2" +version = "1.13.0" description = "Optional static typing for Python" optional = false python-versions = ">=3.8" files = [ - {file = "mypy-1.11.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d42a6dd818ffce7be66cce644f1dff482f1d97c53ca70908dff0b9ddc120b77a"}, - {file = "mypy-1.11.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:801780c56d1cdb896eacd5619a83e427ce436d86a3bdf9112527f24a66618fef"}, - {file = "mypy-1.11.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:41ea707d036a5307ac674ea172875f40c9d55c5394f888b168033177fce47383"}, - {file = "mypy-1.11.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6e658bd2d20565ea86da7d91331b0eed6d2eee22dc031579e6297f3e12c758c8"}, - {file = "mypy-1.11.2-cp310-cp310-win_amd64.whl", hash = "sha256:478db5f5036817fe45adb7332d927daa62417159d49783041338921dcf646fc7"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75746e06d5fa1e91bfd5432448d00d34593b52e7e91a187d981d08d1f33d4385"}, - {file = "mypy-1.11.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a976775ab2256aadc6add633d44f100a2517d2388906ec4f13231fafbb0eccca"}, - {file = "mypy-1.11.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd953f221ac1379050a8a646585a29574488974f79d8082cedef62744f0a0104"}, - {file = "mypy-1.11.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:57555a7715c0a34421013144a33d280e73c08df70f3a18a552938587ce9274f4"}, - {file = "mypy-1.11.2-cp311-cp311-win_amd64.whl", hash = "sha256:36383a4fcbad95f2657642a07ba22ff797de26277158f1cc7bd234821468b1b6"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e8960dbbbf36906c5c0b7f4fbf2f0c7ffb20f4898e6a879fcf56a41a08b0d318"}, - {file = "mypy-1.11.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:06d26c277962f3fb50e13044674aa10553981ae514288cb7d0a738f495550b36"}, - {file = "mypy-1.11.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6e7184632d89d677973a14d00ae4d03214c8bc301ceefcdaf5c474866814c987"}, - {file = "mypy-1.11.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3a66169b92452f72117e2da3a576087025449018afc2d8e9bfe5ffab865709ca"}, - {file = "mypy-1.11.2-cp312-cp312-win_amd64.whl", hash = "sha256:969ea3ef09617aff826885a22ece0ddef69d95852cdad2f60c8bb06bf1f71f70"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:37c7fa6121c1cdfcaac97ce3d3b5588e847aa79b580c1e922bb5d5d2902df19b"}, - {file = "mypy-1.11.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a8a53bc3ffbd161b5b2a4fff2f0f1e23a33b0168f1c0778ec70e1a3d66deb86"}, - {file = "mypy-1.11.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2ff93107f01968ed834f4256bc1fc4475e2fecf6c661260066a985b52741ddce"}, - {file = "mypy-1.11.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:edb91dded4df17eae4537668b23f0ff6baf3707683734b6a818d5b9d0c0c31a1"}, - {file = "mypy-1.11.2-cp38-cp38-win_amd64.whl", hash = "sha256:ee23de8530d99b6db0573c4ef4bd8f39a2a6f9b60655bf7a1357e585a3486f2b"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:801ca29f43d5acce85f8e999b1e431fb479cb02d0e11deb7d2abb56bdaf24fd6"}, - {file = "mypy-1.11.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:af8d155170fcf87a2afb55b35dc1a0ac21df4431e7d96717621962e4b9192e70"}, - {file = "mypy-1.11.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7821776e5c4286b6a13138cc935e2e9b6fde05e081bdebf5cdb2bb97c9df81d"}, - {file = "mypy-1.11.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:539c570477a96a4e6fb718b8d5c3e0c0eba1f485df13f86d2970c91f0673148d"}, - {file = "mypy-1.11.2-cp39-cp39-win_amd64.whl", hash = "sha256:3f14cd3d386ac4d05c5a39a51b84387403dadbd936e17cb35882134d4f8f0d24"}, - {file = "mypy-1.11.2-py3-none-any.whl", hash = "sha256:b499bc07dbdcd3de92b0a8b29fdf592c111276f6a12fe29c30f6c417dd546d12"}, - {file = "mypy-1.11.2.tar.gz", hash = "sha256:7f9993ad3e0ffdc95c2a14b66dee63729f021968bff8ad911867579c65d13a79"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6607e0f1dd1fb7f0aca14d936d13fd19eba5e17e1cd2a14f808fa5f8f6d8f60a"}, + {file = "mypy-1.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8a21be69bd26fa81b1f80a61ee7ab05b076c674d9b18fb56239d72e21d9f4c80"}, + {file = "mypy-1.13.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7b2353a44d2179846a096e25691d54d59904559f4232519d420d64da6828a3a7"}, + {file = "mypy-1.13.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:0730d1c6a2739d4511dc4253f8274cdd140c55c32dfb0a4cf8b7a43f40abfa6f"}, + {file = "mypy-1.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:c5fc54dbb712ff5e5a0fca797e6e0aa25726c7e72c6a5850cfd2adbc1eb0a372"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:581665e6f3a8a9078f28d5502f4c334c0c8d802ef55ea0e7276a6e409bc0d82d"}, + {file = "mypy-1.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3ddb5b9bf82e05cc9a627e84707b528e5c7caaa1c55c69e175abb15a761cec2d"}, + {file = "mypy-1.13.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20c7ee0bc0d5a9595c46f38beb04201f2620065a93755704e141fcac9f59db2b"}, + {file = "mypy-1.13.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3790ded76f0b34bc9c8ba4def8f919dd6a46db0f5a6610fb994fe8efdd447f73"}, + {file = "mypy-1.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:51f869f4b6b538229c1d1bcc1dd7d119817206e2bc54e8e374b3dfa202defcca"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5c7051a3461ae84dfb5dd15eff5094640c61c5f22257c8b766794e6dd85e72d5"}, + {file = "mypy-1.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:39bb21c69a5d6342f4ce526e4584bc5c197fd20a60d14a8624d8743fffb9472e"}, + {file = "mypy-1.13.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:164f28cb9d6367439031f4c81e84d3ccaa1e19232d9d05d37cb0bd880d3f93c2"}, + {file = "mypy-1.13.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a4c1bfcdbce96ff5d96fc9b08e3831acb30dc44ab02671eca5953eadad07d6d0"}, + {file = "mypy-1.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:a0affb3a79a256b4183ba09811e3577c5163ed06685e4d4b46429a271ba174d2"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a7b44178c9760ce1a43f544e595d35ed61ac2c3de306599fa59b38a6048e1aa7"}, + {file = "mypy-1.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d5092efb8516d08440e36626f0153b5006d4088c1d663d88bf79625af3d1d62"}, + {file = "mypy-1.13.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:de2904956dac40ced10931ac967ae63c5089bd498542194b436eb097a9f77bc8"}, + {file = "mypy-1.13.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:7bfd8836970d33c2105562650656b6846149374dc8ed77d98424b40b09340ba7"}, + {file = "mypy-1.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:9f73dba9ec77acb86457a8fc04b5239822df0c14a082564737833d2963677dbc"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:100fac22ce82925f676a734af0db922ecfea991e1d7ec0ceb1e115ebe501301a"}, + {file = "mypy-1.13.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7bcb0bb7f42a978bb323a7c88f1081d1b5dee77ca86f4100735a6f541299d8fb"}, + {file = "mypy-1.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bde31fc887c213e223bbfc34328070996061b0833b0a4cfec53745ed61f3519b"}, + {file = "mypy-1.13.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:07de989f89786f62b937851295ed62e51774722e5444a27cecca993fc3f9cd74"}, + {file = "mypy-1.13.0-cp38-cp38-win_amd64.whl", hash = "sha256:4bde84334fbe19bad704b3f5b78c4abd35ff1026f8ba72b29de70dda0916beb6"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:0246bcb1b5de7f08f2826451abd947bf656945209b140d16ed317f65a17dc7dc"}, + {file = "mypy-1.13.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7f5b7deae912cf8b77e990b9280f170381fdfbddf61b4ef80927edd813163732"}, + {file = "mypy-1.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7029881ec6ffb8bc233a4fa364736789582c738217b133f1b55967115288a2bc"}, + {file = "mypy-1.13.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:3e38b980e5681f28f033f3be86b099a247b13c491f14bb8b1e1e134d23bb599d"}, + {file = "mypy-1.13.0-cp39-cp39-win_amd64.whl", hash = "sha256:a6789be98a2017c912ae6ccb77ea553bbaf13d27605d2ca20a76dfbced631b24"}, + {file = "mypy-1.13.0-py3-none-any.whl", hash = "sha256:9c250883f9fd81d212e0952c92dbfcc96fc237f4b7c92f56ac81fd48460b3e5a"}, + {file = "mypy-1.13.0.tar.gz", hash = "sha256:0291a61b6fbf3e6673e3405cfcc0e7650bebc7939659fdca2702958038bd835e"}, ] [package.dependencies] @@ -763,6 +796,7 @@ typing-extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] mypyc = ["setuptools (>=50)"] reports = ["lxml"] @@ -806,21 +840,21 @@ testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0, [[package]] name = "networkx" -version = "3.1" +version = "3.2.1" description = "Python package for creating and manipulating graphs and networks" optional = true -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, - {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, + {file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"}, + {file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"}, ] [package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] -test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] +default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"] +developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"] +doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"] +test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] name = "orjson" @@ -891,46 +925,46 @@ files = [ [[package]] name = "packaging" -version = "23.1" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "pathspec" -version = "0.11.2" +version = "0.12.1" description = "Utility library for gitignore style pattern matching of file paths." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, ] [[package]] name = "pbr" -version = "5.11.1" +version = "6.1.0" description = "Python Build Reasonableness" optional = false python-versions = ">=2.6" files = [ - {file = "pbr-5.11.1-py2.py3-none-any.whl", hash = "sha256:567f09558bae2b3ab53cb3c1e2e33e726ff3338e7bae3db5dc954b3a44eef12b"}, - {file = "pbr-5.11.1.tar.gz", hash = "sha256:aefc51675b0b533d56bb5fd1c8c6c0522fe31896679882e1c4c63d5e4a0fccb3"}, + {file = "pbr-6.1.0-py2.py3-none-any.whl", hash = "sha256:a776ae228892d8013649c0aeccbb3d5f99ee15e005a4cbb7e61d55a067b28a2a"}, + {file = "pbr-6.1.0.tar.gz", hash = "sha256:788183e382e3d1d7707db08978239965e8b9e4e5ed42669bf4758186734d5f24"}, ] [[package]] name = "pip" -version = "24.2" +version = "24.3.1" description = "The PyPA recommended tool for installing Python packages." optional = false python-versions = ">=3.8" files = [ - {file = "pip-24.2-py3-none-any.whl", hash = "sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2"}, - {file = "pip-24.2.tar.gz", hash = "sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8"}, + {file = "pip-24.3.1-py3-none-any.whl", hash = "sha256:3790624780082365f47549d032f3770eeb2b1e8bd1f7b2e02dace1afa361b4ed"}, + {file = "pip-24.3.1.tar.gz", hash = "sha256:ebcb60557f2aefabc2e0f918751cd24ea0d56d8ec5445fe1807f1d2109660b99"}, ] [[package]] @@ -959,18 +993,19 @@ testing = ["flit_core (>=2,<4)", "poetry_core (>=1.0.0)", "pytest (>=7.2.0)", "p [[package]] name = "platformdirs" -version = "3.10.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" 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-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" @@ -989,27 +1024,27 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pygments" -version = "2.16.1" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, - {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] +windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyparsing" -version = "3.1.4" +version = "3.2.0" description = "pyparsing module - Classes and methods to define and execute parsing grammars" optional = false -python-versions = ">=3.6.8" +python-versions = ">=3.9" files = [ - {file = "pyparsing-3.1.4-py3-none-any.whl", hash = "sha256:a6a7ee4235a3f944aa1fa2249307708f893fe5717dc603503c6c7969c070fb7c"}, - {file = "pyparsing-3.1.4.tar.gz", hash = "sha256:f86ec8d1a83f11977c9a6ea7598e8c27fc5cddfa5b07ea2241edbbde1d7bc032"}, + {file = "pyparsing-3.2.0-py3-none-any.whl", hash = "sha256:93d9577b88da0bbea8cc8334ee8b918ed014968fd2ec383e868fb8afb1ccef84"}, + {file = "pyparsing-3.2.0.tar.gz", hash = "sha256:cbf74e27246d595d9a74b186b810f6fbb86726dbf3b9532efb343f6d7294fe9c"}, ] [package.extras] @@ -1066,86 +1101,77 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] -[[package]] -name = "pytz" -version = "2023.3" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, - {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, -] - [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1214,38 +1240,39 @@ files = [ [[package]] name = "sphinx" -version = "7.1.2" +version = "7.4.7" description = "Python documentation generator" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"}, - {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.21" +alabaster = ">=0.7.14,<0.8.0" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.13" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +importlib-metadata = {version = ">=6.0", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" +sphinxcontrib-serializinghtml = ">=1.1.9" +tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-autodoc-typehints" @@ -1283,47 +1310,50 @@ Sphinx = ">=5.0.0" [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.4" +version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, - {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +version = "2.0.0" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.1" +version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, - {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -1342,54 +1372,56 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +version = "2.0.0" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +version = "2.0.0" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "tomli" -version = "2.0.1" +version = "2.0.2" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, + {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, ] [[package]] name = "types-setuptools" -version = "71.1.0.20240723" +version = "71.1.0.20240818" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" files = [ - {file = "types-setuptools-71.1.0.20240723.tar.gz", hash = "sha256:8a9349038c7e22d88e6c5d9c6705b347b22930424114a452c1712899e85131ff"}, - {file = "types_setuptools-71.1.0.20240723-py3-none-any.whl", hash = "sha256:ac9fc263f59d1e02bca49cb7270a12c47ab80b3b911fb4d92f1fecf978bfe88a"}, + {file = "types-setuptools-71.1.0.20240818.tar.gz", hash = "sha256:f62eaffaa39774462c65fbb49368c4dc1d91a90a28371cb14e1af090ff0e41e3"}, + {file = "types_setuptools-71.1.0.20240818-py3-none-any.whl", hash = "sha256:c4f95302f88369ac0ac46c67ddbfc70c6c4dbbb184d9fed356244217a2934025"}, ] [[package]] @@ -1405,18 +1437,18 @@ files = [ [[package]] name = "urllib3" -version = "2.0.4" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" 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.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] @@ -1436,27 +1468,31 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] [[package]] name = "zipp" -version = "3.16.2" +version = "3.20.2" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.8" files = [ - {file = "zipp-3.16.2-py3-none-any.whl", hash = "sha256:679e51dd4403591b2d6838a48de3d283f3d188412a9782faadf845f298736ba0"}, - {file = "zipp-3.16.2.tar.gz", hash = "sha256:ebc15946aa78bd63458992fc81ec3b6f7b1e92d51c35e6de1c3804e73b799147"}, + {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, + {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-ignore-flaky", "pytest-mypy (>=0.9.1)", "pytest-ruff"] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more-itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] [extras] berkeleydb = ["berkeleydb"] html = ["html5rdf"] -lxml = ["lxml"] +lxml = ["lxml", "lxml"] networkx = ["networkx"] orjson = ["orjson"] [metadata] lock-version = "2.0" -python-versions = "^3.8.1" -content-hash = "0718a437065a928b337f8e182e19f39d8a00dcf478d1a6c76c3bfd83bbc46d93" +python-versions = ">=3.9,<4" +content-hash = "a9ad2786815898a69ec4674f12aefb5c20d97e7597d459c14d0818b412bceece" diff --git a/pyproject.toml b/pyproject.toml index dedced9a9..27d6bb922 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "rdflib" -version = "7.1.2a0" +version = "8.0.0a0" description = """RDFLib is a Python library for working with RDF, \ a simple yet powerful language for representing information.""" authors = ["Daniel 'eikeon' Krech "] @@ -15,6 +15,7 @@ classifiers=[ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", "License :: OSI Approved :: BSD License", "Topic :: Software Development :: Libraries :: Python Modules", "Operating System :: OS Independent", @@ -38,18 +39,21 @@ rdfs2dot = 'rdflib.tools.rdfs2dot:main' rdfgraphisomorphism = 'rdflib.tools.graphisomorphism:main' [tool.poetry.dependencies] -python = "^3.8.1" +python = ">=3.9,<4" isodate = {version=">=0.7.2,<1.0.0", python = "<3.11"} -pyparsing = ">=2.1.0,<4" +pyparsing = ">=3.2.0,<4" berkeleydb = {version = "^18.1.0", optional = true} networkx = {version = ">=2,<4", optional = true} html5rdf = {version = ">=1.2.1,<2", optional = true} -lxml = {version = ">=4.3,<6.0", optional = true} +lxml = [ + {version = ">=4.8.0,<6.0", optional = true, python = "<3.11"}, + {version = ">=4.9.3,<6.0", optional = true, python = ">=3.11"} +] orjson = {version = ">=3.9.14,<4", optional = true} [tool.poetry.group.dev.dependencies] -black = "24.4.2" -mypy = "^1.1.0" +black = "24.10.0" +mypy = "^1.13.0" lxml-stubs = ">=0.4,<0.6" pip-tools = "^7.4.1" @@ -66,10 +70,10 @@ sphinx = ">=7.1.2,<8" myst-parser = ">=2,<4" sphinxcontrib-apidoc = ">=0.3,<0.6" sphinx-autodoc-typehints = ">=1.25.3,<=2.0.1" -typing-extensions = "^4.5.0" +typing-extensions = "^4.11.0" [tool.poetry.group.lint.dependencies] -ruff = ">=0.0.286,<0.8.0" +ruff = ">=0.7.1,<0.8.0" [tool.poetry.extras] berkeleydb = ["berkeleydb"] @@ -81,12 +85,12 @@ lxml = ["lxml"] orjson = ["orjson"] [build-system] -requires = ["poetry-core>=1.4.0"] +requires = ["poetry-core>=1.9.1"] build-backend = "poetry.core.masonry.api" [tool.ruff] # https://beta.ruff.rs/docs/configuration/ -target-version = "py38" +target-version = "py39" # Same as Black. line-length = 88 @@ -167,8 +171,8 @@ ignore = [ [tool.black] line-length = "88" -target-version = ['py38'] -required-version = "24.4.2" +target-version = ['py39'] +required-version = "24.10.0" include = '\.pyi?$' exclude = ''' ( @@ -223,7 +227,7 @@ log_cli_date_format = "%Y-%m-%dT%H:%M:%S" [tool.isort] profile = "black" -py_version = 37 +py_version = 39 line_length = 88 src_paths= ["rdflib", "test", "devtools", "examples"] supported_extensions = ["pyw", "pyi", "py"] @@ -250,7 +254,7 @@ skip = [ [tool.mypy] files = ['rdflib', 'test', 'devtools', 'examples'] -python_version = "3.8" +python_version = "3.9" warn_unused_configs = true ignore_missing_imports = true disallow_subclassing_any = false diff --git a/rdflib/_networking.py b/rdflib/_networking.py index 311096a89..d70b7e061 100644 --- a/rdflib/_networking.py +++ b/rdflib/_networking.py @@ -2,7 +2,6 @@ import string import sys -from typing import Dict from urllib.error import HTTPError from urllib.parse import quote as urlquote from urllib.parse import urljoin, urlsplit @@ -68,7 +67,7 @@ def _make_redirect_request(request: Request, http_error: HTTPError) -> Request: unverifiable=True, ) - visited: Dict[str, int] + visited: dict[str, int] if hasattr(request, "redirect_dict"): visited = request.redirect_dict if ( diff --git a/rdflib/collection.py b/rdflib/collection.py index ed0a48ff9..054fdb481 100644 --- a/rdflib/collection.py +++ b/rdflib/collection.py @@ -1,12 +1,14 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Iterable, Iterator, List, Optional +from typing import TYPE_CHECKING, Optional, cast from rdflib.namespace import RDF -from rdflib.term import BNode, Node +from rdflib.term import BNode, IdentifiedNode if TYPE_CHECKING: - from rdflib.graph import Graph + from collections.abc import Iterable, Iterator + + from rdflib.graph import Graph, _ObjectType __all__ = ["Collection"] @@ -54,7 +56,10 @@ class Collection: (``http://www.w3.org/1999/02/22-rdf-syntax-ns#nil``). """ - def __init__(self, graph: Graph, uri: Node, seq: List[Node] = []): + uri: IdentifiedNode + graph: Graph + + def __init__(self, graph: Graph, uri: IdentifiedNode, seq: list[_ObjectType] = []): self.graph = graph self.uri = uri or BNode() if seq: @@ -88,24 +93,26 @@ def n3(self) -> str: """ return "( %s )" % (" ".join([i.n3() for i in self])) - def _get_container(self, index: int) -> Optional[Node]: + def _get_container(self, index: int) -> Optional[IdentifiedNode]: """Gets the first, rest holding node at index.""" assert isinstance(index, int) graph = self.graph - container: Optional[Node] = self.uri + container: Optional[IdentifiedNode] = self.uri i = 0 - while i < index: + while i < index and container is not None: i += 1 - container = graph.value(container, RDF.rest) - if container is None: - break + ret = graph.value(container, RDF.rest) + if ret is not None: + container = cast(IdentifiedNode, ret) + else: + container = None return container def __len__(self) -> int: """length of items in collection.""" return len(list(self.graph.items(self.uri))) - def index(self, item: Node) -> int: + def index(self, item: _ObjectType) -> int: """ Returns the 0-based numerical index of the item in the list """ @@ -123,9 +130,9 @@ def index(self, item: Node) -> int: raise Exception("Malformed RDF Collection: %s" % self.uri) else: assert len(newlink) == 1, "Malformed RDF Collection: %s" % self.uri - listname = newlink[0] + listname = cast(IdentifiedNode, newlink[0]) - def __getitem__(self, key: int) -> Node: + def __getitem__(self, key: int) -> _ObjectType: """TODO""" c = self._get_container(key) if c: @@ -137,7 +144,7 @@ def __getitem__(self, key: int) -> Node: else: raise IndexError(key) - def __setitem__(self, key: int, value: Node) -> None: + def __setitem__(self, key: int, value: _ObjectType) -> None: """TODO""" c = self._get_container(key) if c: @@ -207,21 +214,21 @@ def __delitem__(self, key: int) -> None: graph.remove((current, None, None)) graph.set((prior, RDF.rest, next)) - def __iter__(self) -> Iterator[Node]: + def __iter__(self) -> Iterator[_ObjectType]: """Iterator over items in Collections""" return self.graph.items(self.uri) - def _end(self) -> Node: + def _end(self) -> IdentifiedNode: # find end of list - container = self.uri + container: IdentifiedNode = self.uri while True: rest = self.graph.value(container, RDF.rest) if rest is None or rest == RDF.nil: return container else: - container = rest + container = cast(IdentifiedNode, rest) - def append(self, item: Node) -> Collection: + def append(self, item: _ObjectType) -> Collection: """ >>> from rdflib.term import Literal >>> from rdflib.graph import Graph @@ -249,7 +256,7 @@ def append(self, item: Node) -> Collection: self.graph.add((end, RDF.rest, RDF.nil)) return self - def __iadd__(self, other: Iterable[Node]): + def __iadd__(self, other: Iterable[_ObjectType]): end = self._end() if end == RDF.nil: raise ValueError("Cannot append to empty list") @@ -267,11 +274,11 @@ def __iadd__(self, other: Iterable[Node]): return self def clear(self): - container: Optional[Node] = self.uri + container: Optional[IdentifiedNode] = self.uri graph = self.graph - while container: + while container is not None: rest = graph.value(container, RDF.rest) graph.remove((container, RDF.first, None)) graph.remove((container, RDF.rest, None)) - container = rest + container = cast(Optional[IdentifiedNode], rest) return self diff --git a/rdflib/compare.py b/rdflib/compare.py index afc2c40b5..1ba765cd9 100644 --- a/rdflib/compare.py +++ b/rdflib/compare.py @@ -90,19 +90,10 @@ ] from collections import defaultdict +from collections.abc import Callable, Iterator from datetime import datetime from hashlib import sha256 -from typing import ( - TYPE_CHECKING, - Callable, - Dict, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) +from typing import TYPE_CHECKING, Optional, Union from rdflib.graph import ConjunctiveGraph, Graph, ReadOnlyGraphAggregate, _TripleType from rdflib.term import BNode, IdentifiedNode, Node, URIRef @@ -202,16 +193,16 @@ def internal_hash(self, stats=None): HashFunc = Callable[[str], int] -ColorItem = Tuple[Union[int, str], URIRef, Union[int, str]] -ColorItemTuple = Tuple[ColorItem, ...] -HashCache = Optional[Dict[ColorItemTuple, str]] -Stats = Dict[str, Union[int, str]] +ColorItem = tuple[Union[int, str], URIRef, Union[int, str]] +ColorItemTuple = tuple[ColorItem, ...] +HashCache = Optional[dict[ColorItemTuple, str]] +Stats = dict[str, Union[int, str]] class Color: def __init__( self, - nodes: List[IdentifiedNode], + nodes: list[IdentifiedNode], hashfunc: HashFunc, color: ColorItemTuple = (), hash_cache: HashCache = None, @@ -231,7 +222,7 @@ def __str__(self): def key(self): return (len(self.nodes), self.hash_color()) - def hash_color(self, color: Optional[Tuple[ColorItem, ...]] = None) -> str: + def hash_color(self, color: Optional[tuple[ColorItem, ...]] = None) -> str: if color is None: color = self.color if color in self._hash_cache: @@ -253,9 +244,9 @@ def stringify(x): return val def distinguish(self, W: Color, graph: Graph): # noqa: N803 - colors: Dict[str, Color] = {} + colors: dict[str, Color] = {} for n in self.nodes: - new_color: Tuple[ColorItem, ...] = list(self.color) # type: ignore[assignment] + new_color: tuple[ColorItem, ...] = list(self.color) # type: ignore[assignment] for node in W.nodes: new_color += [ # type: ignore[operator] (1, p, W.hash_color()) for s, p, o in graph.triples((n, None, node)) @@ -296,10 +287,10 @@ def _hashfunc(s: str): self._hash_cache: HashCache = {} self.hashfunc = _hashfunc - def _discrete(self, coloring: List[Color]) -> bool: + def _discrete(self, coloring: list[Color]) -> bool: return len([c for c in coloring if not c.discrete()]) == 0 - def _initial_color(self) -> List[Color]: + def _initial_color(self) -> list[Color]: """Finds an initial color for the graph. Finds an initial color of the graph by finding all blank nodes and @@ -307,7 +298,7 @@ def _initial_color(self) -> List[Color]: nodes are not included, as they are a) already colored (by URI or literal) and b) do not factor into the color of any blank node. """ - bnodes: Set[BNode] = set() + bnodes: set[BNode] = set() others = set() self._neighbors = defaultdict(set) for s, p, o in self.graph: @@ -343,12 +334,12 @@ def _individuate(self, color, individual): ) return c - def _get_candidates(self, coloring: List[Color]) -> Iterator[Tuple[Node, Color]]: + def _get_candidates(self, coloring: list[Color]) -> Iterator[tuple[Node, Color]]: for c in [c for c in coloring if not c.discrete()]: for node in c.nodes: yield node, c - def _refine(self, coloring: List[Color], sequence: List[Color]) -> List[Color]: + def _refine(self, coloring: list[Color], sequence: list[Color]) -> list[Color]: sequence = sorted(sequence, key=lambda x: x.key(), reverse=True) coloring = coloring[:] while len(sequence) > 0 and not self._discrete(coloring): @@ -367,8 +358,8 @@ def _refine(self, coloring: List[Color], sequence: List[Color]) -> List[Color]: sequence = sequence[:si] + colors + sequence[si + 1 :] except ValueError: sequence = colors[1:] + sequence - combined_colors: List[Color] = [] - combined_color_map: Dict[str, Color] = dict() + combined_colors: list[Color] = [] + combined_color_map: dict[str, Color] = dict() for color in coloring: color_hash = color.hash_color() # This is a hash collision, and be combined into a single color for individuation. @@ -388,7 +379,7 @@ def to_hash(self, stats: Optional[Stats] = None): stats["graph_digest"] = "%x" % result return result - def _experimental_path(self, coloring: List[Color]) -> List[Color]: + def _experimental_path(self, coloring: list[Color]) -> list[Color]: coloring = [c.copy() for c in coloring] while not self._discrete(coloring): color = [x for x in coloring if not x.discrete()][0] @@ -400,9 +391,9 @@ def _experimental_path(self, coloring: List[Color]) -> List[Color]: def _create_generator( self, - colorings: List[List[Color]], - groupings: Optional[Dict[Node, Set[Node]]] = None, - ) -> Dict[Node, Set[Node]]: + colorings: list[list[Color]], + groupings: Optional[dict[Node, set[Node]]] = None, + ) -> dict[Node, set[Node]]: if not groupings: groupings = defaultdict(set) for group in zip(*colorings): @@ -416,20 +407,20 @@ def _create_generator( @_call_count("individuations") def _traces( self, - coloring: List[Color], + coloring: list[Color], stats: Optional[Stats] = None, - depth: List[int] = [0], - ) -> List[Color]: + depth: list[int] = [0], + ) -> list[Color]: if stats is not None and "prunings" not in stats: stats["prunings"] = 0 depth[0] += 1 candidates = self._get_candidates(coloring) - best: List[List[Color]] = [] + best: list[list[Color]] = [] best_score = None best_experimental_score = None last_coloring = None - generator: Dict[Node, Set[Node]] = defaultdict(set) - visited: Set[Node] = set() + generator: dict[Node, set[Node]] = defaultdict(set) + visited: set[Node] = set() for candidate, color in candidates: if candidate in generator: v = generator[candidate] & visited @@ -437,7 +428,7 @@ def _traces( visited.add(candidate) continue visited.add(candidate) - coloring_copy: List[Color] = [] + coloring_copy: list[Color] = [] color_copy = None for c in coloring: c_copy = c.copy() @@ -469,7 +460,7 @@ def _traces( # prune this branch. if stats is not None: stats["prunings"] += 1 - discrete: List[List[Color]] = [x for x in best if self._discrete(x)] + discrete: list[list[Color]] = [x for x in best if self._discrete(x)] if len(discrete) == 0: best_score = None best_depth = None @@ -509,7 +500,7 @@ def canonical_triples(self, stats: Optional[Stats] = None): if stats is not None: stats["color_count"] = len(coloring) - bnode_labels: Dict[Node, str] = dict( + bnode_labels: dict[Node, str] = dict( [(c.nodes[0], c.hash_color()) for c in coloring] ) if stats is not None: @@ -523,7 +514,7 @@ def canonical_triples(self, stats: Optional[Stats] = None): def _canonicalize_bnodes( self, triple: _TripleType, - labels: Dict[Node, str], + labels: dict[Node, str], ): for term in triple: if isinstance(term, BNode): @@ -591,7 +582,7 @@ def to_canonical_graph( return ReadOnlyGraphAggregate([graph]) -def graph_diff(g1: Graph, g2: Graph) -> Tuple[Graph, Graph, Graph]: +def graph_diff(g1: Graph, g2: Graph) -> tuple[Graph, Graph, Graph]: """Returns three sets of triples: "in both", "in first" and "in second".""" # bnodes have deterministic values in canonical graphs: cg1 = to_canonical_graph(g1) diff --git a/rdflib/compat.py b/rdflib/compat.py index ddb55eb0b..dcab51798 100644 --- a/rdflib/compat.py +++ b/rdflib/compat.py @@ -8,7 +8,7 @@ import codecs import re import warnings -from typing import Match +from re import Match def cast_bytes(s, enc="utf-8"): diff --git a/rdflib/events.py b/rdflib/events.py index 61f3454b6..07d6e6475 100644 --- a/rdflib/events.py +++ b/rdflib/events.py @@ -25,7 +25,7 @@ from __future__ import annotations -from typing import Any, Dict, Optional +from typing import Any, Optional __all__ = ["Event", "Dispatcher"] @@ -57,9 +57,9 @@ class Dispatcher: subscribers. """ - _dispatch_map: Optional[Dict[Any, Any]] = None + _dispatch_map: Optional[dict[Any, Any]] = None - def set_map(self, amap: Dict[Any, Any]): + def set_map(self, amap: dict[Any, Any]): self._dispatch_map = amap return self diff --git a/rdflib/extras/external_graph_libs.py b/rdflib/extras/external_graph_libs.py index 42469778e..c03beff2b 100644 --- a/rdflib/extras/external_graph_libs.py +++ b/rdflib/extras/external_graph_libs.py @@ -12,7 +12,7 @@ from __future__ import annotations import logging -from typing import TYPE_CHECKING, Any, Dict, List +from typing import TYPE_CHECKING, Any if TYPE_CHECKING: from rdflib.graph import Graph @@ -255,8 +255,8 @@ def rdflib_to_networkx_graph( def rdflib_to_graphtool( graph: Graph, - v_prop_names: List[str] = ["term"], - e_prop_names: List[str] = ["term"], + v_prop_names: list[str] = ["term"], + e_prop_names: list[str] = ["term"], transform_s=lambda s, p, o: {"term": s}, transform_p=lambda s, p, o: {"term": p}, transform_o=lambda s, p, o: {"term": o}, @@ -328,7 +328,7 @@ def rdflib_to_graphtool( eprops = [(epn, g.new_edge_property("object")) for epn in e_prop_names] for epn, eprop in eprops: g.edge_properties[epn] = eprop - node_to_vertex: Dict[Any, Any] = {} + node_to_vertex: dict[Any, Any] = {} for s, p, o in graph: sv = node_to_vertex.get(s) if sv is None: diff --git a/rdflib/extras/infixowl.py b/rdflib/extras/infixowl.py index b80fb0c16..bc2db9179 100644 --- a/rdflib/extras/infixowl.py +++ b/rdflib/extras/infixowl.py @@ -117,14 +117,17 @@ import itertools import logging -from typing import Iterable, Union +from typing import TYPE_CHECKING, Optional, Union, cast from rdflib.collection import Collection from rdflib.graph import Graph, _ObjectType from rdflib.namespace import OWL, RDF, RDFS, XSD, Namespace, NamespaceManager -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable +from rdflib.term import BNode, IdentifiedNode, Identifier, Literal, URIRef, Variable from rdflib.util import first +if TYPE_CHECKING: + from collections.abc import Iterable + logger = logging.getLogger(__name__) @@ -371,13 +374,19 @@ class Individual: """ + # Class variable factoryGraph = Graph() # noqa: N815 + # Instance typing + graph: Graph + __identifier: IdentifiedNode + qname: Optional[str] + def serialize(self, graph): for fact in self.factoryGraph.triples((self.identifier, None, None)): graph.add(fact) - def __init__(self, identifier=None, graph=None): + def __init__(self, identifier: Optional[IdentifiedNode] = None, graph=None): self.__identifier = identifier is not None and identifier or BNode() if graph is None: self.graph = self.factoryGraph @@ -465,11 +474,10 @@ def _delete_type(self): type = property(_get_type, _set_type, _delete_type) - def _get_identifier(self) -> Identifier: + def _get_identifier(self) -> IdentifiedNode: return self.__identifier - def _set_identifier(self, i: Identifier): - assert i + def _set_identifier(self, i: IdentifiedNode): if i != self.__identifier: oldstatements_out = [ (p, o) @@ -597,7 +605,7 @@ class AnnotatableTerms(Individual): def __init__( self, - identifier, + identifier: Optional[IdentifiedNode], graph=None, nameAnnotation=None, # noqa: N803 nameIsLabel=False, # noqa: N803 @@ -653,10 +661,13 @@ def _get_comment(self): ): yield comment - def _set_comment(self, comment): + def _set_comment( + self, + comment: Optional[IdentifiedNode | Literal | list[IdentifiedNode | Literal]], + ): if not comment: return - if isinstance(comment, Identifier): + if isinstance(comment, (IdentifiedNode, Literal)): self.graph.add((self.identifier, RDFS.comment, comment)) else: for c in comment: @@ -690,10 +701,12 @@ def _get_label(self): for label in self.graph.objects(subject=self.identifier, predicate=RDFS.label): yield label - def _set_label(self, label): + def _set_label( + self, label: Optional[IdentifiedNode | Literal | list[IdentifiedNode | Literal]] + ): if not label: return - if isinstance(label, Identifier): + if isinstance(label, (IdentifiedNode, Literal)): self.graph.add((self.identifier, RDFS.label, label)) else: for l_ in label: @@ -1045,7 +1058,7 @@ def setupNounAnnotations(self, noun_annotations): # noqa: N802 def __init__( self, - identifier=None, + identifier: Optional[IdentifiedNode] = None, subClassOf=None, # noqa: N803 equivalentClass=None, # noqa: N803 disjointWith=None, # noqa: N803 @@ -1174,7 +1187,10 @@ def _get_subclassof(self): for anc in self.graph.objects( subject=self.identifier, predicate=RDFS.subClassOf ): - yield Class(anc, graph=self.graph, skipOWLClassMembership=True) + # We must assume all objects we get back are URIRef or BNodes + yield Class( + cast(IdentifiedNode, anc), graph=self.graph, skipOWLClassMembership=True + ) def _set_subclassof(self, other): if not other: @@ -1194,7 +1210,7 @@ def _get_equivalentclass(self): for ec in self.graph.objects( subject=self.identifier, predicate=OWL.equivalentClass ): - yield Class(ec, graph=self.graph) + yield Class(cast(IdentifiedNode, ec), graph=self.graph) def _set_equivalentclass(self, other): if not other: @@ -1216,7 +1232,7 @@ def _get_disjointwith(self): for dc in self.graph.objects( subject=self.identifier, predicate=OWL.disjointWith ): - yield Class(dc, graph=self.graph) + yield Class(cast(IdentifiedNode, dc), graph=self.graph) def _set_disjointwith(self, other): if not other: @@ -1239,7 +1255,7 @@ def _get_complementof(self): if not comp: return None elif len(comp) == 1: - return Class(comp[0], graph=self.graph) + return Class(cast(IdentifiedNode, comp[0]), graph=self.graph) else: raise Exception(len(comp)) @@ -1310,7 +1326,7 @@ def isPrimitive(self): # noqa: N802 # sc = list(self.subClassOf) ec = list(self.equivalentClass) for _boolclass, p, rdf_list in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, list[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" (self.identifier, [OWL.intersectionOf, OWL.unionOf], None) # type: ignore[arg-type] ): ec.append(manchesterSyntax(rdf_list, self.graph, boolean=p)) @@ -1340,7 +1356,7 @@ def manchesterClass(self, full=False, normalization=True): # noqa: N802 sc = list(self.subClassOf) ec = list(self.equivalentClass) for _boolclass, p, rdf_list in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, list[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" (self.identifier, [OWL.intersectionOf, OWL.unionOf], None) # type: ignore[arg-type] ): ec.append(manchesterSyntax(rdf_list, self.graph, boolean=p)) @@ -1349,10 +1365,8 @@ def manchesterClass(self, full=False, normalization=True): # noqa: N802 if c: dc.append(c) klasskind = "" - label = list(self.graph.objects(self.identifier, RDFS.label)) - # type error: Incompatible types in assignment (expression has type "str", variable has type "List[Node]") - # type error: Unsupported operand types for + ("str" and "Node") - label = label and "(" + label[0] + ")" or "" # type: ignore[assignment, operator] + label_list = list(self.graph.objects(self.identifier, RDFS.label)) + label = "" if len(label_list) < 1 else "(" + label_list[0] + ")" if sc: if full: scjoin = "\n " @@ -1748,27 +1762,34 @@ class Restriction(Class): def __init__( self, onProperty, # noqa: N803 - graph=None, - allValuesFrom=None, # noqa: N803 - someValuesFrom=None, # noqa: N803 - value=None, - cardinality=None, - maxCardinality=None, # noqa: N803 - minCardinality=None, # noqa: N803 - identifier=None, + graph: Optional[Graph] = None, + allValuesFrom: Optional[ # noqa: N803 + IdentifiedNode | Literal | Class | bool + ] = None, + someValuesFrom: Optional[ # noqa: N803 + IdentifiedNode | Literal | Class | bool + ] = None, + value: Optional[IdentifiedNode | Literal | Class | bool] = None, + cardinality: Optional[IdentifiedNode | Literal | Class | bool] = None, + maxCardinality: Optional[ # noqa: N803 + IdentifiedNode | Literal | Class | bool + ] = None, + minCardinality: Optional[ # noqa: N803 + IdentifiedNode | Literal | Class | bool + ] = None, + identifier: Optional[IdentifiedNode] = None, ): graph = Graph() if graph is None else graph super(Restriction, self).__init__( identifier, graph=graph, skipOWLClassMembership=True ) + self_id_node: IdentifiedNode = self.identifier if ( - self.identifier, + self_id_node, OWL.onProperty, propertyOrIdentifier(onProperty), ) not in graph: - graph.add( - (self.identifier, OWL.onProperty, propertyOrIdentifier(onProperty)) - ) + graph.add((self_id_node, OWL.onProperty, propertyOrIdentifier(onProperty))) self.onProperty = onProperty restr_types = [ (allValuesFrom, OWL.allValuesFrom), @@ -1787,7 +1808,7 @@ def __init__( ) restriction_range, restriction_type = valid_restr_props.pop() self.restrictionType = restriction_type - if isinstance(restriction_range, Identifier): + if isinstance(restriction_range, (IdentifiedNode, Literal)): self.restrictionRange = restriction_range elif isinstance(restriction_range, Class): self.restrictionRange = classOrIdentifier(restriction_range) @@ -1795,18 +1816,18 @@ def __init__( # error: Incompatible types in assignment (expression has type "Optional[Identifier]", variable has type "Identifier") self.restrictionRange = first( # type: ignore[assignment] # type error: Argument 1 to "first" has incompatible type "Generator[Node, None, None]"; expected "Iterable[Identifier]" - self.graph.objects(self.identifier, restriction_type) # type: ignore[arg-type] + self.graph.objects(self_id_node, restriction_type) # type: ignore[arg-type] ) if ( - self.identifier, + self_id_node, restriction_type, self.restrictionRange, ) not in self.graph: - self.graph.add((self.identifier, restriction_type, self.restrictionRange)) - assert self.restrictionRange is not None, Class(self.identifier) - if (self.identifier, RDF.type, OWL.Restriction) not in self.graph: - self.graph.add((self.identifier, RDF.type, OWL.Restriction)) - self.graph.remove((self.identifier, RDF.type, OWL.Class)) + self.graph.add((self_id_node, restriction_type, self.restrictionRange)) + assert self.restrictionRange is not None, Class(self_id_node) + if (self_id_node, RDF.type, OWL.Restriction) not in self.graph: + self.graph.add((self_id_node, RDF.type, OWL.Restriction)) + self.graph.remove((self_id_node, RDF.type, OWL.Class)) def serialize(self, graph): """ @@ -1883,7 +1904,7 @@ def _get_allvaluesfrom(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL.allValuesFrom ): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_allvaluesfrom(self, other): @@ -1907,7 +1928,7 @@ def _get_somevaluesfrom(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL.someValuesFrom ): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_somevaluesfrom(self, other): @@ -1929,7 +1950,7 @@ def _del_somevaluesfrom(self): def _get_hasvalue(self): for i in self.graph.objects(subject=self.identifier, predicate=OWL.hasValue): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_hasvalue(self, other): @@ -1949,7 +1970,7 @@ def _del_hasvalue(self): def _get_cardinality(self): for i in self.graph.objects(subject=self.identifier, predicate=OWL.cardinality): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_cardinality(self, other): @@ -1971,7 +1992,7 @@ def _get_maxcardinality(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL.maxCardinality ): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_maxcardinality(self, other): @@ -1995,7 +2016,7 @@ def _get_mincardinality(self): for i in self.graph.objects( subject=self.identifier, predicate=OWL.minCardinality ): - return Class(i, graph=self.graph) + return Class(cast(IdentifiedNode, i), graph=self.graph) return None def _set_mincardinality(self, other): @@ -2016,12 +2037,12 @@ def _del_mincardinality(self): ) def restrictionKind(self): # noqa: N802 + self_id_node: IdentifiedNode = self.identifier for s, p, o in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, List[URIRef], None]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" - (self.identifier, self.restrictionKinds, None) # type: ignore[arg-type] + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type + (self_id_node, self.restrictionKinds, None) # type: ignore[arg-type] ): - # type error: "Node" has no attribute "split" - return p.split(str(OWL))[-1] # type: ignore[attr-defined] + return p.split(str(OWL))[-1] return None def __repr__(self): @@ -2190,7 +2211,7 @@ def __repr__(self): ) ) for _s, _p, roletype in self.graph.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, URIRef, List[URIRef]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Any, URIRef, list[URIRef]]"; expected "Union[Tuple[List[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" ( # type: ignore[arg-type] self.identifier, RDF.type, @@ -2201,8 +2222,7 @@ def __repr__(self): ], ) ): - # type error: "Node" has no attribute "split" - rt.append(str(roletype.split(str(OWL))[-1])) # type: ignore[attr-defined] + rt.append(str(roletype).split(str(OWL), 1)[-1]) else: rt.append( "DatatypeProperty( %s %s" @@ -2296,7 +2316,7 @@ def _del_inverseof(self): def _get_domain(self): for dom in self.graph.objects(subject=self.identifier, predicate=RDFS.domain): - yield Class(dom, graph=self.graph) + yield Class(cast(IdentifiedNode, dom), graph=self.graph) def _set_domain(self, other): if not other: @@ -2315,7 +2335,7 @@ def _del_domain(self): def _get_range(self): for ran in self.graph.objects(subject=self.identifier, predicate=RDFS.range): - yield Class(ran, graph=self.graph) + yield Class(cast(IdentifiedNode, ran), graph=self.graph) def _set_range(self, ranges): if not ranges: diff --git a/rdflib/extras/shacl.py b/rdflib/extras/shacl.py index 30fdab07b..dd8ca5498 100644 --- a/rdflib/extras/shacl.py +++ b/rdflib/extras/shacl.py @@ -4,12 +4,14 @@ from __future__ import annotations -from typing import Optional, Union +from typing import TYPE_CHECKING, Optional from rdflib import Graph, Literal, URIRef, paths from rdflib.namespace import RDF, SH from rdflib.paths import Path -from rdflib.term import Node + +if TYPE_CHECKING: + from rdflib.graph import _ObjectType class SHACLPathError(Exception): @@ -20,8 +22,8 @@ class SHACLPathError(Exception): # pyshacl.helper.sparql_query_helper::SPARQLQueryHelper._shacl_path_to_sparql_path def parse_shacl_path( shapes_graph: Graph, - path_identifier: Node, -) -> Union[URIRef, Path]: + path_identifier: _ObjectType, +) -> URIRef | Path: """ Parse a valid SHACL path (e.g. the object of a triple with predicate sh:path) from a :class:`~rdflib.graph.Graph` as a :class:`~rdflib.term.URIRef` if the path @@ -31,7 +33,7 @@ def parse_shacl_path( :param path_identifier: A :class:`~rdflib.term.Node` of the path :return: A :class:`~rdflib.term.URIRef` or a :class:`~rdflib.paths.Path` """ - path: Optional[Union[URIRef, Path]] = None + path: Optional[URIRef | Path] = None # Literals are not allowed. if isinstance(path_identifier, Literal): diff --git a/rdflib/graph.py b/rdflib/graph.py index 80ccc3fa8..cc36a6e82 100644 --- a/rdflib/graph.py +++ b/rdflib/graph.py @@ -259,18 +259,9 @@ TYPE_CHECKING, Any, BinaryIO, - Callable, - Dict, - Generator, - Iterable, - List, - Mapping, NoReturn, Optional, - Set, TextIO, - Tuple, - Type, TypeVar, Union, cast, @@ -279,12 +270,12 @@ from urllib.parse import urlparse from urllib.request import url2pathname +import rdflib.collection # avoid circular dependency import rdflib.exceptions as exceptions import rdflib.namespace as namespace # noqa: F401 # This is here because it is used in a docstring. import rdflib.plugin as plugin -import rdflib.query as query +import rdflib.query import rdflib.util # avoid circular dependency -from rdflib.collection import Collection from rdflib.exceptions import ParserError from rdflib.namespace import RDF, Namespace, NamespaceManager from rdflib.parser import InputSource, Parser, create_input_source @@ -301,39 +292,46 @@ Node, RDFLibGenid, URIRef, + Variable, ) if TYPE_CHECKING: + from collections.abc import Callable, Generator, Iterable, Mapping + import typing_extensions as te - import rdflib.query from rdflib.plugins.sparql.sparql import Query, Update -_SubjectType = Node -_PredicateType = Node -_ObjectType = Node +# RDFLib official stance is Subject can be a Literal +# If this ever changes, this part will be one of the first lines to modify. +_SubjectType: te.TypeAlias = Union[IdentifiedNode, Literal, Variable] +_PredicateType: te.TypeAlias = Union[IdentifiedNode, Variable] +_ObjectType: te.TypeAlias = Union[IdentifiedNode, Literal, Variable] _ContextIdentifierType = IdentifiedNode -_TripleType = Tuple["_SubjectType", "_PredicateType", "_ObjectType"] -_QuadType = Tuple["_SubjectType", "_PredicateType", "_ObjectType", "_ContextType"] -_OptionalQuadType = Tuple[ +_TripleType: te.TypeAlias = tuple[_SubjectType, _PredicateType, _ObjectType] +_QuadType: te.TypeAlias = tuple[ + "_SubjectType", "_PredicateType", "_ObjectType", "_ContextType" +] +_OptionalQuadType = tuple[ "_SubjectType", "_PredicateType", "_ObjectType", Optional["_ContextType"] ] _TripleOrOptionalQuadType = Union["_TripleType", "_OptionalQuadType"] -_OptionalIdentifiedQuadType = Tuple[ +_OptionalQuadQuotedType: te.TypeAlias = Union[_OptionalQuadType, "QuotedGraph"] +_OptionalIdentifiedQuadType = tuple[ "_SubjectType", "_PredicateType", "_ObjectType", Optional["_ContextIdentifierType"] ] -_TriplePatternType = Tuple[ +_TriplePatternType = tuple[ Optional["_SubjectType"], Optional["_PredicateType"], Optional["_ObjectType"] ] -_TriplePathPatternType = Tuple[Optional["_SubjectType"], Path, Optional["_ObjectType"]] -_QuadPatternType = Tuple[ +_TriplePathPatternType = tuple[Optional["_SubjectType"], Path, Optional["_ObjectType"]] +_QuadPatternType = tuple[ Optional["_SubjectType"], Optional["_PredicateType"], Optional["_ObjectType"], Optional["_ContextType"], ] -_QuadPathPatternType = Tuple[ +_QuadPathPatternType = tuple[ Optional["_SubjectType"], Path, Optional["_ObjectType"], @@ -341,24 +339,31 @@ ] _TripleOrQuadPatternType = Union["_TriplePatternType", "_QuadPatternType"] _TripleOrQuadPathPatternType = Union["_TriplePathPatternType", "_QuadPathPatternType"] -_TripleSelectorType = Tuple[ + +# The difference between TriplePattern and TripleSelector is that +# TripleSelector can have a Optional[Path] as the predicate, and Subject/Object +# can be a QuaotedGraph +_TripleSelectorType = tuple[ Optional["_SubjectType"], - Optional[Union["Path", "_PredicateType"]], + Optional[Union[Path, "_PredicateType"]], Optional["_ObjectType"], ] -_QuadSelectorType = Tuple[ +_QuadSelectorType = tuple[ Optional["_SubjectType"], - Optional[Union["Path", "_PredicateType"]], + Optional[Union[Path, "_PredicateType"]], Optional["_ObjectType"], Optional["_ContextType"], ] _TripleOrQuadSelectorType = Union["_TripleSelectorType", "_QuadSelectorType"] -_TriplePathType = Tuple["_SubjectType", Path, "_ObjectType"] +_TriplePathType = tuple["_SubjectType", Path, "_ObjectType"] _TripleOrTriplePathType = Union["_TripleType", "_TriplePathType"] _GraphT = TypeVar("_GraphT", bound="Graph") _ConjunctiveGraphT = TypeVar("_ConjunctiveGraphT", bound="ConjunctiveGraph") _DatasetT = TypeVar("_DatasetT", bound="Dataset") +_QuotedGraphT = TypeVar("_QuotedGraphT", bound="QuotedGraph") + +_builtin_set_t = set # type error: Function "Type[Literal]" could always be true in boolean contex assert Literal # type: ignore[truthy-function] # avoid warning @@ -410,6 +415,8 @@ _TCArgT = TypeVar("_TCArgT") +# Graph is a node because technically a formula-aware graph +# take a Graph as subject or object, but we usually use QuotedGraph for that. class Graph(Node): """An RDF Graph @@ -440,8 +447,8 @@ class Graph(Node): def __init__( self, - store: Union[Store, str] = "default", - identifier: Optional[Union[_ContextIdentifierType, str]] = None, + store: Store | str = "default", + identifier: Optional[_ContextIdentifierType | str] = None, namespace_manager: Optional[NamespaceManager] = None, base: Optional[str] = None, bind_namespaces: _NamespaceSetString = "rdflib", @@ -464,6 +471,15 @@ def __init__( self.formula_aware = False self.default_union = False + def __getnewargs__(self) -> tuple[Any, ...]: + return ( + self.store, + self.__identifier, + self.__namespace_manager, + self.base, + self._bind_namespaces, + ) + @property def store(self) -> Store: return self.__store @@ -786,7 +802,7 @@ def __xor__(self, other: Graph) -> Graph: # Conv. methods def set( - self: _GraphT, triple: Tuple[_SubjectType, _PredicateType, _ObjectType] + self: _GraphT, triple: tuple[_SubjectType, _PredicateType, _ObjectType] ) -> _GraphT: """Convenience method to update the value of object @@ -806,7 +822,7 @@ def set( def subjects( self, - predicate: Union[None, Path, _PredicateType] = None, + predicate: Optional[Path | _PredicateType] = None, object: Optional[_ObjectType] = None, unique: bool = False, ) -> Generator[_SubjectType, None, None]: @@ -855,7 +871,7 @@ def predicates( def objects( self, subject: Optional[_SubjectType] = None, - predicate: Union[None, Path, _PredicateType] = None, + predicate: Optional[Path | _PredicateType] = None, unique: bool = False, ) -> Generator[_ObjectType, None, None]: """A generator of (optionally unique) objects with the given @@ -878,7 +894,7 @@ def objects( def subject_predicates( self, object: Optional[_ObjectType] = None, unique: bool = False - ) -> Generator[Tuple[_SubjectType, _PredicateType], None, None]: + ) -> Generator[tuple[_SubjectType, _PredicateType], None, None]: """A generator of (optionally unique) (subject, predicate) tuples for the given object""" if not unique: @@ -899,9 +915,9 @@ def subject_predicates( def subject_objects( self, - predicate: Union[None, Path, _PredicateType] = None, + predicate: Optional[Path | _PredicateType] = None, unique: bool = False, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + ) -> Generator[tuple[_SubjectType, _ObjectType], None, None]: """A generator of (optionally unique) (subject, object) tuples for the given predicate""" if not unique: @@ -922,7 +938,7 @@ def subject_objects( def predicate_objects( self, subject: Optional[_SubjectType] = None, unique: bool = False - ) -> Generator[Tuple[_PredicateType, _ObjectType], None, None]: + ) -> Generator[tuple[_PredicateType, _ObjectType], None, None]: """A generator of (optionally unique) (predicate, object) tuples for the given subject""" if not unique: @@ -943,15 +959,27 @@ def predicate_objects( def triples_choices( self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], + triple: ( + tuple[ + list[_SubjectType] | tuple[_SubjectType], + _PredicateType, + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + list[_PredicateType] | tuple[_PredicateType], + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + _PredicateType, + list[_ObjectType] | tuple[_ObjectType], + ] + ), context: Optional[_ContextType] = None, ) -> Generator[_TripleType, None, None]: subject, predicate, object_ = triple - # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "tuple[Union[list[Node], Node], Union[Node, list[Node]], Union[Node, list[Node]]]"; expected "Union[tuple[list[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" # type error note: unpacking discards type info for (s, p, o), cg in self.store.triples_choices( (subject, predicate, object_), context=self # type: ignore[arg-type] @@ -988,6 +1016,36 @@ def value( any: bool = ..., ) -> None: ... + @overload + def value( + self, + subject: None = ..., + predicate: Optional[_PredicateType] = ..., + object: Optional[_ObjectType] = ..., + default: Optional[_SubjectType] = ..., + any: bool = ..., + ) -> Optional[_SubjectType]: ... + + @overload + def value( + self, + subject: Optional[_SubjectType] = ..., + predicate: None = ..., + object: Optional[_ObjectType] = ..., + default: Optional[_PredicateType] = ..., + any: bool = ..., + ) -> Optional[_PredicateType]: ... + + @overload + def value( + self, + subject: Optional[_SubjectType] = ..., + predicate: Optional[_PredicateType] = ..., + object: None = ..., + default: Optional[_ObjectType] = ..., + any: bool = ..., + ) -> Optional[_ObjectType]: ... + @overload def value( self, @@ -1063,7 +1121,7 @@ def value( pass return retval - def items(self, list: Node) -> Generator[Node, None, None]: + def items(self, list: _SubjectType) -> Generator[_ObjectType, None, None]: """Generator over all items in the resource specified by list list is an RDF collection. @@ -1083,7 +1141,7 @@ def transitiveClosure( # noqa: N802 self, func: Callable[[_TCArgT, Graph], Iterable[_TCArgT]], arg: _TCArgT, - seen: Optional[Dict[_TCArgT, int]] = None, + seen: Optional[dict[_TCArgT, int]] = None, ): """ Generates transitive closure of a user-defined @@ -1145,7 +1203,7 @@ def transitive_objects( self, subject: Optional[_SubjectType], predicate: Optional[_PredicateType], - remember: Optional[Dict[Optional[_SubjectType], int]] = None, + remember: Optional[dict[Optional[_SubjectType], int]] = None, ) -> Generator[Optional[_SubjectType], None, None]: """Transitively generate objects for the ``predicate`` relationship @@ -1166,7 +1224,7 @@ def transitive_subjects( self, predicate: Optional[_PredicateType], object: Optional[_ObjectType], - remember: Optional[Dict[Optional[_ObjectType], int]] = None, + remember: Optional[dict[Optional[_ObjectType], int]] = None, ) -> Generator[Optional[_ObjectType], None, None]: """Transitively generate subjects for the ``predicate`` relationship @@ -1186,7 +1244,7 @@ def transitive_subjects( def qname(self, uri: str) -> str: return self.namespace_manager.qname(uri) - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: + def compute_qname(self, uri: str, generate: bool = True) -> tuple[str, URIRef, str]: return self.namespace_manager.compute_qname(uri, generate) def bind( @@ -1217,7 +1275,7 @@ def bind( prefix, namespace, override=override, replace=replace ) - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: + def namespaces(self) -> Generator[tuple[str, URIRef], None, None]: """Generator over all the prefix, namespace tuples""" for prefix, namespace in self.namespace_manager.namespaces(): # noqa: F402 yield prefix, namespace @@ -1264,7 +1322,7 @@ def serialize( @overload def serialize( self, - destination: Union[str, pathlib.PurePath, IO[bytes]], + destination: str | pathlib.PurePath | IO[bytes], format: str = ..., base: Optional[str] = ..., encoding: Optional[str] = ..., @@ -1275,21 +1333,21 @@ def serialize( @overload def serialize( self, - destination: Optional[Union[str, pathlib.PurePath, IO[bytes]]] = ..., + destination: Optional[str | pathlib.PurePath | IO[bytes]] = ..., format: str = ..., base: Optional[str] = ..., encoding: Optional[str] = ..., **args: Any, - ) -> Union[bytes, str, Graph]: ... + ) -> bytes | str | Graph: ... def serialize( self: _GraphT, - destination: Optional[Union[str, pathlib.PurePath, IO[bytes]]] = None, + destination: Optional[str | pathlib.PurePath | IO[bytes]] = None, format: str = "turtle", base: Optional[str] = None, encoding: Optional[str] = None, **args: Any, - ) -> Union[bytes, str, _GraphT]: + ) -> bytes | str | _GraphT: """ Serialize the graph. @@ -1372,13 +1430,13 @@ def print( def parse( self, source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] + IO[bytes] | TextIO | InputSource | str | bytes | pathlib.PurePath ] = None, publicID: Optional[str] = None, # noqa: N803 format: Optional[str] = None, location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, + file: Optional[BinaryIO | TextIO] = None, + data: Optional[str | bytes] = None, **args: Any, ) -> Graph: """ @@ -1516,14 +1574,14 @@ def parse( def query( self, - query_object: Union[str, Query], - processor: Union[str, query.Processor] = "sparql", - result: Union[str, Type[query.Result]] = "sparql", + query_object: str | Query, + processor: str | rdflib.query.Processor = "sparql", + result: str | type[rdflib.query.Result] = "sparql", initNs: Optional[Mapping[str, Any]] = None, # noqa: N803 initBindings: Optional[Mapping[str, Identifier]] = None, # noqa: N803 use_store_provided: bool = True, **kwargs: Any, - ) -> query.Result: + ) -> rdflib.query.Result: """ Query this graph. @@ -1572,20 +1630,22 @@ def query( except NotImplementedError: pass # store has no own implementation - if not isinstance(result, query.Result): - result = plugin.get(cast(str, result), query.Result) - if not isinstance(processor, query.Processor): - processor = plugin.get(processor, query.Processor)(self) + if not isinstance(result, rdflib.query.Result): + result = plugin.get(cast(str, result), rdflib.query.Result) + if not isinstance(processor, rdflib.query.Processor): + processor = plugin.get(processor, rdflib.query.Processor)(self) # type error: Argument 1 to "Result" has incompatible type "Mapping[str, Any]"; expected "str" return result(processor.query(query_object, initBindings, initNs, **kwargs)) # type: ignore[arg-type] def update( self, - update_object: Union[Update, str], - processor: Union[str, rdflib.query.UpdateProcessor] = "sparql", + update_object: Update | str, + processor: str | rdflib.query.UpdateProcessor = "sparql", initNs: Optional[Mapping[str, Any]] = None, # noqa: N803 - initBindings: Optional[Mapping[str, Identifier]] = None, # noqa: N803 + initBindings: Optional[ # noqa: N803 + Mapping[str, rdflib.query.QueryBindingsValueType] + ] = None, use_store_provided: bool = True, **kwargs: Any, ) -> None: @@ -1627,8 +1687,8 @@ def update( except NotImplementedError: pass # store has no own implementation - if not isinstance(processor, query.UpdateProcessor): - processor = plugin.get(processor, query.UpdateProcessor)(self) + if not isinstance(processor, rdflib.query.UpdateProcessor): + processor = plugin.get(processor, rdflib.query.UpdateProcessor)(self) return processor.update(update_object, initBindings, initNs, **kwargs) @@ -1636,7 +1696,7 @@ def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: """Return an n3 identifier for the Graph""" return "[%s]" % self.identifier.n3(namespace_manager=namespace_manager) - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: + def __reduce__(self) -> tuple[type[Graph], tuple[Store, _ContextIdentifierType]]: return ( Graph, ( @@ -1703,12 +1763,12 @@ def connected(self) -> bool: else: return False - def all_nodes(self) -> Set[Node]: + def all_nodes(self) -> _builtin_set_t[_SubjectType | _ObjectType]: res = set(self.objects()) res.update(self.subjects()) return res - def collection(self, identifier: _SubjectType) -> Collection: + def collection(self, identifier: IdentifiedNode) -> rdflib.collection.Collection: """Create a new ``Collection`` instance. Parameters: @@ -1720,15 +1780,14 @@ def collection(self, identifier: _SubjectType) -> Collection: >>> graph = Graph() >>> uri = URIRef("http://example.org/resource") >>> collection = graph.collection(uri) - >>> assert isinstance(collection, Collection) + >>> assert isinstance(collection, rdflib.collection.Collection) >>> assert collection.uri is uri >>> assert collection.graph is graph >>> collection += [ Literal(1), Literal(2) ] """ + return rdflib.collection.Collection(self, identifier) - return Collection(self, identifier) - - def resource(self, identifier: Union[Node, str]) -> Resource: + def resource(self, identifier: Node | str) -> Resource: """Create a new ``Resource`` instance. Parameters: @@ -1811,18 +1870,14 @@ def do_de_skolemize2(t: _TripleType) -> _TripleType: (s, p, o) = t if RDFLibGenid._is_rdflib_skolem(s): - # type error: Argument 1 to "RDFLibGenid" has incompatible type "Node"; expected "str" - s = RDFLibGenid(s).de_skolemize() # type: ignore[arg-type] + s = RDFLibGenid(s).de_skolemize() elif Genid._is_external_skolem(s): - # type error: Argument 1 to "Genid" has incompatible type "Node"; expected "str" - s = Genid(s).de_skolemize() # type: ignore[arg-type] + s = Genid(s).de_skolemize() if RDFLibGenid._is_rdflib_skolem(o): - # type error: Argument 1 to "RDFLibGenid" has incompatible type "Node"; expected "str" - o = RDFLibGenid(o).de_skolemize() # type: ignore[arg-type] + o = RDFLibGenid(o).de_skolemize() elif Genid._is_external_skolem(o): - # type error: Argument 1 to "Genid" has incompatible type "Node"; expected "str" - o = Genid(o).de_skolemize() # type: ignore[arg-type] + o = Genid(o).de_skolemize() return s, p, o @@ -1920,8 +1975,8 @@ class ConjunctiveGraph(Graph): def __init__( self, - store: Union[Store, str] = "default", - identifier: Optional[Union[IdentifiedNode, str]] = None, + store: Store | str = "default", + identifier: Optional[IdentifiedNode | str] = None, default_graph_base: Optional[str] = None, ): super(ConjunctiveGraph, self).__init__(store, identifier=identifier) @@ -1942,6 +1997,9 @@ def __init__( store=self.store, identifier=identifier or BNode(), base=default_graph_base ) + def __getnewargs__(self) -> tuple[Any, ...]: + return (self.store, self.__identifier, self.default_context.base) + def __str__(self) -> str: pattern = ( "[a rdflib:ConjunctiveGraph;rdflib:storage " @@ -1959,7 +2017,7 @@ def _spoc( @overload def _spoc( self, - triple_or_quad: Union[_TripleType, _OptionalQuadType], + triple_or_quad: _TripleType | _OptionalQuadType, default: bool = False, ) -> _OptionalQuadType: ... @@ -1968,7 +2026,7 @@ def _spoc( self, triple_or_quad: None, default: bool = False, - ) -> Tuple[None, None, None, Optional[Graph]]: ... + ) -> tuple[None, None, None, Optional[Graph]]: ... @overload def _spoc( @@ -2038,13 +2096,13 @@ def add( return self @overload - def _graph(self, c: Union[Graph, _ContextIdentifierType, str]) -> Graph: ... + def _graph(self, c: Graph | _ContextIdentifierType | str) -> Graph: ... @overload def _graph(self, c: None) -> None: ... def _graph( - self, c: Optional[Union[Graph, _ContextIdentifierType, str]] + self, c: Optional[Graph | _ContextIdentifierType | str] ) -> Optional[Graph]: if c is None: return None @@ -2063,7 +2121,7 @@ def addN( # noqa: N802 ) return self - # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "Tuple[Optional[Node], Optional[Node], Optional[Node]]" + # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "tuple[Optional[Node], Optional[Node], Optional[Node]]" def remove(self: _ConjunctiveGraphT, triple_or_quad: _TripleOrOptionalQuadType) -> _ConjunctiveGraphT: # type: ignore[override] """ Removes a triple or quads @@ -2145,11 +2203,23 @@ def quads( def triples_choices( self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], + triple: ( + tuple[ + list[_SubjectType] | tuple[_SubjectType], + _PredicateType, + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + list[_PredicateType] | tuple[_PredicateType], + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + _PredicateType, + list[_ObjectType] | tuple[_ObjectType], + ] + ), context: Optional[_ContextType] = None, ) -> Generator[_TripleType, None, None]: """Iterate over all the triples in the entire conjunctive graph""" @@ -2159,7 +2229,7 @@ def triples_choices( context = self.default_context else: context = self._graph(context) - # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Store" has incompatible type "tuple[Union[list[Node], Node], Union[Node, list[Node]], Union[Node, list[Node]]]"; expected "Union[tuple[list[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" # type error note: unpacking discards type info for (s1, p1, o1), cg in self.store.triples_choices((s, p, o), context=context): # type: ignore[arg-type] yield s1, p1, o1 @@ -2185,13 +2255,13 @@ def contexts( # type error: Statement is unreachable yield self.get_context(context) # type: ignore[unreachable] - def get_graph(self, identifier: _ContextIdentifierType) -> Union[Graph, None]: + def get_graph(self, identifier: _ContextIdentifierType) -> Optional[Graph]: """Returns the graph identified by given identifier""" return [x for x in self.contexts() if x.identifier == identifier][0] def get_context( self, - identifier: Optional[Union[_ContextIdentifierType, str]], + identifier: Optional[_ContextIdentifierType | str], quoted: bool = False, base: Optional[str] = None, ) -> Graph: @@ -2220,13 +2290,13 @@ def context_id(self, uri: str, context_id: Optional[str] = None) -> URIRef: def parse( self, source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] + IO[bytes] | TextIO | InputSource | str | bytes | pathlib.PurePath ] = None, publicID: Optional[str] = None, # noqa: N803 format: Optional[str] = None, location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, + file: Optional[BinaryIO | TextIO] = None, + data: Optional[str | bytes] = None, **args: Any, ) -> Graph: """ @@ -2288,7 +2358,7 @@ def parse( # TODO: FIXME: This should not return context, but self. return context - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: + def __reduce__(self) -> tuple[type[Graph], tuple[Store, _ContextIdentifierType]]: return ConjunctiveGraph, (self.store, self.identifier) @@ -2420,14 +2490,14 @@ class Dataset(ConjunctiveGraph): def __init__( self, - store: Union[Store, str] = "default", + store: Store | str = "default", default_union: bool = False, default_graph_base: Optional[str] = None, ): super(Dataset, self).__init__(store=store, identifier=None) if not self.store.graph_aware: - raise Exception("DataSet must be backed by a graph-aware store!") + raise Exception("Dataset must be backed by a graph-aware store!") self.default_context = Graph( store=self.store, identifier=DATASET_DEFAULT_GRAPH_ID, @@ -2436,22 +2506,25 @@ def __init__( self.default_union = default_union + def __getnewargs__(self) -> tuple[Any, ...]: + return (self.store, self.default_union, self.default_context.base) + def __str__(self) -> str: pattern = ( "[a rdflib:Dataset;rdflib:storage " "[a rdflib:Store;rdfs:label '%s']]" ) return pattern % self.store.__class__.__name__ - # type error: Return type "Tuple[Type[Dataset], Tuple[Store, bool]]" of "__reduce__" incompatible with return type "Tuple[Type[Graph], Tuple[Store, IdentifiedNode]]" in supertype "ConjunctiveGraph" - # type error: Return type "Tuple[Type[Dataset], Tuple[Store, bool]]" of "__reduce__" incompatible with return type "Tuple[Type[Graph], Tuple[Store, IdentifiedNode]]" in supertype "Graph" - def __reduce__(self) -> Tuple[Type[Dataset], Tuple[Store, bool]]: # type: ignore[override] - return (type(self), (self.store, self.default_union)) + # type error: Return type "tuple[Type[Dataset], tuple[Store, bool]]" of "__reduce__" incompatible with return type "tuple[Type[Graph], tuple[Store, IdentifiedNode]]" in supertype "ConjunctiveGraph" + # type error: Return type "tuple[Type[Dataset], tuple[Store, bool]]" of "__reduce__" incompatible with return type "tuple[Type[Graph], tuple[Store, IdentifiedNode]]" in supertype "Graph" + def __reduce__(self) -> tuple[type[Dataset], tuple[Store, bool]]: # type: ignore[override] + return type(self), (self.store, self.default_union) - def __getstate__(self) -> Tuple[Store, _ContextIdentifierType, _ContextType, bool]: + def __getstate__(self) -> tuple[Store, _ContextIdentifierType, _ContextType, bool]: return self.store, self.identifier, self.default_context, self.default_union def __setstate__( - self, state: Tuple[Store, _ContextIdentifierType, _ContextType, bool] + self, state: tuple[Store, _ContextIdentifierType, _ContextType, bool] ) -> None: # type error: Property "store" defined in "Graph" is read-only # type error: Property "identifier" defined in "Graph" is read-only @@ -2459,7 +2532,7 @@ def __setstate__( def graph( self, - identifier: Optional[Union[_ContextIdentifierType, _ContextType, str]] = None, + identifier: Optional[_ContextIdentifierType | _ContextType | str] = None, base: Optional[str] = None, ) -> Graph: if identifier is None: @@ -2481,13 +2554,13 @@ def graph( def parse( self, source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] + IO[bytes] | TextIO | InputSource | str | bytes | pathlib.PurePath ] = None, publicID: Optional[str] = None, # noqa: N803 format: Optional[str] = None, location: Optional[str] = None, - file: Optional[Union[BinaryIO, TextIO]] = None, - data: Optional[Union[str, bytes]] = None, + file: Optional[BinaryIO | TextIO] = None, + data: Optional[str | bytes] = None, **args: Any, ) -> Graph: """ @@ -2530,13 +2603,13 @@ def parse( return c def add_graph( - self, g: Optional[Union[_ContextIdentifierType, _ContextType, str]] + self, g: Optional[_ContextIdentifierType | _ContextType | str] ) -> Graph: """alias of graph for consistency""" return self.graph(g) def remove_graph( - self: _DatasetT, g: Optional[Union[_ContextIdentifierType, _ContextType, str]] + self: _DatasetT, g: Optional[_ContextIdentifierType | _ContextType | str] ) -> _DatasetT: if not isinstance(g, Graph): g = self.get_context(g) @@ -2560,7 +2633,7 @@ def contexts( graphs = contexts - # type error: Return type "Generator[Tuple[Node, Node, Node, Optional[Node]], None, None]" of "quads" incompatible with return type "Generator[Tuple[Node, Node, Node, Optional[Graph]], None, None]" in supertype "ConjunctiveGraph" + # type error: Return type "Generator[tuple[Node, Node, Node, Optional[Node]], None, None]" of "quads" incompatible with return type "Generator[tuple[Node, Node, Node, Optional[Graph]], None, None]" in supertype "ConjunctiveGraph" def quads( # type: ignore[override] self, quad: Optional[_TripleOrQuadPatternType] = None ) -> Generator[_OptionalIdentifiedQuadType, None, None]: @@ -2572,7 +2645,7 @@ def quads( # type: ignore[override] # type error: Item "None" of "Optional[Graph]" has no attribute "identifier" [union-attr] yield s, p, o, c.identifier # type: ignore[union-attr] - # type error: Return type "Generator[Tuple[Node, URIRef, Node, Optional[IdentifiedNode]], None, None]" of "__iter__" incompatible with return type "Generator[Tuple[IdentifiedNode, IdentifiedNode, Union[IdentifiedNode, Literal]], None, None]" in supertype "Graph" + # type error: Return type "Generator[tuple[Node, URIRef, Node, Optional[IdentifiedNode]], None, None]" of "__iter__" incompatible with return type "Generator[tuple[IdentifiedNode, IdentifiedNode, Union[IdentifiedNode, Literal]], None, None]" in supertype "Graph" def __iter__( # type: ignore[override] self, ) -> Generator[_OptionalIdentifiedQuadType, None, None]: @@ -2580,7 +2653,7 @@ def __iter__( # type: ignore[override] return self.quads((None, None, None, None)) -class QuotedGraph(Graph): +class QuotedGraph(Graph, IdentifiedNode): """ Quoted Graphs are intended to implement Notation 3 formulae. They are associated with a required identifier that the N3 parser *must* provide @@ -2588,14 +2661,17 @@ class QuotedGraph(Graph): such as implication and other such processing. """ - def __init__( - self, - store: Union[Store, str], - identifier: Optional[Union[_ContextIdentifierType, str]], + def __new__( + cls, + store: Store | str, + identifier: Optional[_ContextIdentifierType | str], ): + return str.__new__(cls, identifier) + + def __init__(self, store: Store, identifier: Optional[_ContextIdentifierType]): super(QuotedGraph, self).__init__(store, identifier) - def add(self: _GraphT, triple: _TripleType) -> _GraphT: + def add(self: _QuotedGraphT, triple: _TripleType) -> _QuotedGraphT: """Add a triple with self as context""" s, p, o = triple assert isinstance(s, Node), "Subject %s must be an rdflib term" % (s,) @@ -2605,7 +2681,9 @@ def add(self: _GraphT, triple: _TripleType) -> _GraphT: self.store.add((s, p, o), self, quoted=True) return self - def addN(self: _GraphT, quads: Iterable[_QuadType]) -> _GraphT: # noqa: N802 + def addN( # noqa: N802 + self: _QuotedGraphT, quads: Iterable[_QuadType] + ) -> _QuotedGraphT: """Add a sequence of triple with context""" self.store.addN( @@ -2630,9 +2708,30 @@ def __str__(self) -> str: ) return pattern % (identifier, label) - def __reduce__(self) -> Tuple[Type[Graph], Tuple[Store, _ContextIdentifierType]]: + def __reduce__( + self, + ) -> tuple[type[QuotedGraph], tuple[Store, _ContextIdentifierType]]: return QuotedGraph, (self.store, self.identifier) + def toPython(self: _QuotedGraphT) -> _QuotedGraphT: # noqa: N802 + return self + + # Resolve conflicts between multiple inheritance + __iter__ = Graph.__iter__ # type: ignore[assignment] + __contains__ = Graph.__contains__ # type: ignore[assignment] + __ge__ = Graph.__ge__ # type: ignore[assignment] + __le__ = Graph.__le__ # type: ignore[assignment] + __gt__ = Graph.__gt__ + __eq__ = Graph.__eq__ + __iadd__ = Graph.__iadd__ + __add__ = Graph.__add__ # type: ignore[assignment] + __isub__ = Graph.__isub__ + __sub__ = Graph.__sub__ + __getitem__ = Graph.__getitem__ # type: ignore[assignment] + __len__ = Graph.__len__ + __hash__ = Graph.__hash__ + __mul__ = Graph.__mul__ # type: ignore[assignment] + # Make sure QuotedGraph is ordered correctly # wrt to other Terms. @@ -2662,14 +2761,12 @@ def __init__(self, graph: Graph, subject: _SubjectType): creates this instance! """ - self._list: List[Tuple[int, _ObjectType]] + self._list: list[tuple[int, _ObjectType]] _list = self._list = list() LI_INDEX = URIRef(str(RDF) + "_") # noqa: N806 for p, o in graph.predicate_objects(subject): - # type error: "Node" has no attribute "startswith" - if p.startswith(LI_INDEX): # type: ignore[attr-defined] # != RDF.Seq: - # type error: "Node" has no attribute "replace" - i = int(p.replace(LI_INDEX, "")) # type: ignore[attr-defined] + if p.startswith(LI_INDEX): + i = int(p.replace(LI_INDEX, "")) _list.append((i, o)) # here is the trick: the predicates are _1, _2, _3, etc. Ie, @@ -2720,7 +2817,7 @@ class ReadOnlyGraphAggregate(ConjunctiveGraph): ConjunctiveGraph over an explicit subset of the entire store. """ - def __init__(self, graphs: List[Graph], store: Union[str, Store] = "default"): + def __init__(self, graphs: list[Graph], store: Union[str, Store] = "default"): if store is not None: super(ReadOnlyGraphAggregate, self).__init__(store) Graph.__init__(self, store) @@ -2765,7 +2862,7 @@ def add(self, triple: _TripleOrOptionalQuadType) -> NoReturn: def addN(self, quads: Iterable[_QuadType]) -> NoReturn: # noqa: N802 raise ModificationException() - # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "Tuple[Optional[Node], Optional[Node], Optional[Node]]" + # type error: Argument 1 of "remove" is incompatible with supertype "Graph"; supertype defines the argument type as "tuple[Optional[Node], Optional[Node], Optional[Node]]" def remove(self, triple: _TripleOrOptionalQuadType) -> NoReturn: # type: ignore[override] raise ModificationException() @@ -2816,18 +2913,16 @@ def __contains__(self, triple_or_quad: _TripleOrQuadSelectorType) -> bool: def quads( # type: ignore[override] self, triple_or_quad: _TripleOrQuadSelectorType ) -> Generator[ - Tuple[_SubjectType, Union[Path, _PredicateType], _ObjectType, _ContextType], + tuple[_SubjectType, Path | _PredicateType, _ObjectType, _ContextType], None, None, ]: """Iterate over all the quads in the entire aggregate graph""" c = None if len(triple_or_quad) == 4: - # type error: Need more than 3 values to unpack (4 expected) - s, p, o, c = triple_or_quad # type: ignore[misc, unused-ignore] + s, p, o, c = triple_or_quad else: - # type error: Too many values to unpack (3 expected, 4 provided) - s, p, o = triple_or_quad # type: ignore[misc, unused-ignore] + s, p, o = triple_or_quad[:3] if c is not None: for graph in [g for g in self.graphs if g == c]: @@ -2864,16 +2959,28 @@ def __isub__(self: _GraphT, other: Iterable[_TripleType]) -> NoReturn: def triples_choices( self, - triple: Union[ - Tuple[List[_SubjectType], _PredicateType, _ObjectType], - Tuple[_SubjectType, List[_PredicateType], _ObjectType], - Tuple[_SubjectType, _PredicateType, List[_ObjectType]], - ], + triple: ( + tuple[ + list[_SubjectType] | tuple[_SubjectType], + _PredicateType, + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + list[_PredicateType] | tuple[_PredicateType], + Optional[_ObjectType], + ] + | tuple[ + Optional[_SubjectType], + _PredicateType, + list[_ObjectType] | tuple[_ObjectType], + ] + ), context: Optional[_ContextType] = None, ) -> Generator[_TripleType, None, None]: subject, predicate, object_ = triple for graph in self.graphs: - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Union[List[Node], Node], Union[Node, List[Node]], Union[Node, List[Node]]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "tuple[Union[list[Node], Node], Union[Node, list[Node]], Union[Node, list[Node]]]"; expected "Union[tuple[list[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" # type error note: unpacking discards type info choices = graph.triples_choices((subject, predicate, object_)) # type: ignore[arg-type] for s, p, o in choices: @@ -2884,7 +2991,7 @@ def qname(self, uri: str) -> str: return self.namespace_manager.qname(uri) raise UnSupportedAggregateOperation() - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: + def compute_qname(self, uri: str, generate: bool = True) -> tuple[str, URIRef, str]: if hasattr(self, "namespace_manager") and self.namespace_manager: return self.namespace_manager.compute_qname(uri, generate) raise UnSupportedAggregateOperation() @@ -2895,7 +3002,7 @@ def bind( # type: ignore[override] ) -> NoReturn: raise UnSupportedAggregateOperation() - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: + def namespaces(self) -> Generator[tuple[str, URIRef], None, None]: if hasattr(self, "namespace_manager"): for prefix, namespace in self.namespace_manager.namespaces(): yield prefix, namespace @@ -2911,7 +3018,7 @@ def absolutize(self, uri: str, defrag: int = 1) -> NoReturn: def parse( # type: ignore[override] self, source: Optional[ - Union[IO[bytes], TextIO, InputSource, str, bytes, pathlib.PurePath] + IO[bytes] | TextIO | InputSource | str | bytes | pathlib.PurePath ], publicID: Optional[str] = None, # noqa: N803 format: Optional[str] = None, @@ -2972,17 +3079,11 @@ def reset(self) -> BatchAddGraph: """ Manually clear the buffered triples and reset the count to zero """ - self.batch: List[_QuadType] = [] + self.batch: list[_QuadType] = [] self.count = 0 return self - def add( - self, - triple_or_quad: Union[ - _TripleType, - _QuadType, - ], - ) -> BatchAddGraph: + def add(self, triple_or_quad: _TripleType | _QuadType) -> BatchAddGraph: """ Add a triple to the buffer @@ -2993,10 +3094,10 @@ def add( self.batch = [] self.count += 1 if len(triple_or_quad) == 3: - # type error: Argument 1 to "append" of "list" has incompatible type "Tuple[Node, ...]"; expected "Tuple[Node, Node, Node, Graph]" + # type error: Argument 1 to "append" of "list" has incompatible type "tuple[Node, ...]"; expected "tuple[Node, Node, Node, Graph]" self.batch.append(triple_or_quad + self.__graph_tuple) # type: ignore[arg-type, unused-ignore] else: - # type error: Argument 1 to "append" of "list" has incompatible type "Union[Tuple[Node, Node, Node], Tuple[Node, Node, Node, Graph]]"; expected "Tuple[Node, Node, Node, Graph]" + # type error: Argument 1 to "append" of "list" has incompatible type "Union[tuple[Node, Node, Node], tuple[Node, Node, Node, Graph]]"; expected "tuple[Node, Node, Node, Graph]" self.batch.append(triple_or_quad) # type: ignore[arg-type, unused-ignore] return self diff --git a/rdflib/namespace/__init__.py b/rdflib/namespace/__init__.py index eb8e2eeed..e6d0b1391 100644 --- a/rdflib/namespace/__init__.py +++ b/rdflib/namespace/__init__.py @@ -74,9 +74,10 @@ import logging import warnings +from collections.abc import Iterable from functools import lru_cache from pathlib import Path -from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Set, Tuple, Union +from typing import TYPE_CHECKING, Any, Optional from unicodedata import category from urllib.parse import urldefrag, urljoin @@ -144,7 +145,7 @@ class Namespace(str): False """ - def __new__(cls, value: Union[str, bytes]) -> Namespace: + def __new__(cls, value: str | bytes) -> Namespace: try: rt = str.__new__(cls, value) except UnicodeDecodeError: @@ -202,7 +203,7 @@ class URIPattern(str): """ - def __new__(cls, value: Union[str, bytes]) -> URIPattern: + def __new__(cls, value: str | bytes) -> URIPattern: try: rt = str.__new__(cls, value) except UnicodeDecodeError: @@ -225,7 +226,7 @@ def __repr__(self) -> str: # always raise AttributeError if they are not defined and which should not be # considered part of __dir__ results. These should be all annotations on # `DefinedNamespaceMeta`. -_DFNS_RESERVED_ATTRS: Set[str] = { +_DFNS_RESERVED_ATTRS: set[str] = { "__slots__", "_NS", "_warn", @@ -236,7 +237,7 @@ def __repr__(self) -> str: # Some libraries probe classes for certain attributes or items. # This is a list of those attributes and items that should be ignored. -_IGNORED_ATTR_LOOKUP: Set[str] = { +_IGNORED_ATTR_LOOKUP: set[str] = { "_pytestfixturefunction", # pytest tries to look this up on Defined namespaces "_partialmethod", # sphinx tries to look this up during autodoc generation } @@ -245,12 +246,12 @@ def __repr__(self) -> str: class DefinedNamespaceMeta(type): """Utility metaclass for generating URIRefs with a common prefix.""" - __slots__: Tuple[str, ...] = tuple() + __slots__: tuple[str, ...] = tuple() _NS: Namespace _warn: bool = True _fail: bool = False # True means mimic ClosedNamespace - _extras: List[str] = [] # List of non-pythonesque items + _extras: list[str] = [] # List of non-pythonesque items _underscore_num: bool = False # True means pass "_n" constructs @lru_cache(maxsize=None) @@ -340,7 +341,7 @@ class DefinedNamespace(metaclass=DefinedNamespaceMeta): Warnings are emitted if unknown members are referenced if _warn is True """ - __slots__: Tuple[str, ...] = tuple() + __slots__: tuple[str, ...] = tuple() def __init__(self): raise TypeError("namespace may not be instantiated") @@ -353,9 +354,9 @@ class ClosedNamespace(Namespace): Trying to create terms not listed is an error """ - __uris: Dict[str, URIRef] + __uris: dict[str, URIRef] - def __new__(cls, uri: str, terms: List[str]): + def __new__(cls, uri: str, terms: list[str]): rt = super().__new__(cls, uri) rt.__uris = {t: URIRef(rt + t) for t in terms} # type: ignore[attr-defined] return rt @@ -385,7 +386,7 @@ def __getattr__(self, name: str) -> URIRef: def __repr__(self) -> str: return f"{self.__module__}.{self.__class__.__name__}({str(self)!r})" - def __dir__(self) -> List[str]: + def __dir__(self) -> list[str]: return list(self.__uris) def __contains__(self, ref: str) -> bool: # type: ignore[override] @@ -393,7 +394,7 @@ def __contains__(self, ref: str) -> bool: # type: ignore[override] ref in self.__uris.values() ) # test namespace membership with "ref in ns" syntax - def _ipython_key_completions_(self) -> List[str]: + def _ipython_key_completions_(self) -> list[str]: return dir(self) @@ -457,11 +458,11 @@ class NamespaceManager: def __init__(self, graph: Graph, bind_namespaces: _NamespaceSetString = "rdflib"): self.graph = graph - self.__cache: Dict[str, Tuple[str, URIRef, str]] = {} - self.__cache_strict: Dict[str, Tuple[str, URIRef, str]] = {} + self.__cache: dict[str, tuple[str, URIRef, str]] = {} + self.__cache_strict: dict[str, tuple[str, URIRef, str]] = {} self.__log = None - self.__strie: Dict[str, Any] = {} - self.__trie: Dict[str, Any] = {} + self.__strie: dict[str, Any] = {} + self.__trie: dict[str, Any] = {} # This type declaration is here becuase there is no common base class # for all namespaces and without it the inferred type of ns is not # compatible with all prefixes. @@ -578,7 +579,7 @@ def normalizeUri(self, rdfTerm: str) -> str: # noqa: N802, N803 qNameParts = self.compute_qname(rdfTerm) # noqa: N806 return ":".join([qNameParts[0], qNameParts[-1]]) - def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, str]: + def compute_qname(self, uri: str, generate: bool = True) -> tuple[str, URIRef, str]: prefix: Optional[str] if uri not in self.__cache: if not _is_valid_uri(uri): @@ -625,7 +626,7 @@ def compute_qname(self, uri: str, generate: bool = True) -> Tuple[str, URIRef, s def compute_qname_strict( self, uri: str, generate: bool = True - ) -> Tuple[str, str, str]: + ) -> tuple[str, str, str]: # code repeated to avoid branching on strict every time # if output needs to be strict (e.g. for xml) then # only the strict output should bear the overhead @@ -794,7 +795,7 @@ def bind( insert_trie(self.__trie, str(namespace)) - def namespaces(self) -> Iterable[Tuple[str, URIRef]]: + def namespaces(self) -> Iterable[tuple[str, URIRef]]: for prefix, namespace in self.store.namespaces(): namespace = URIRef(namespace) yield prefix, namespace @@ -877,8 +878,8 @@ def is_ncname(name: str) -> int: def split_uri( - uri: str, split_start: List[str] = SPLIT_START_CATEGORIES -) -> Tuple[str, str]: + uri: str, split_start: list[str] = SPLIT_START_CATEGORIES +) -> tuple[str, str]: if uri.startswith(XMLNS): return (XMLNS, uri.split(XMLNS)[1]) length = len(uri) @@ -900,8 +901,8 @@ def split_uri( def insert_trie( - trie: Dict[str, Any], value: str -) -> Dict[str, Any]: # aka get_subtrie_or_insert + trie: dict[str, Any], value: str +) -> dict[str, Any]: # aka get_subtrie_or_insert """Insert a value into the trie if it is not already contained in the trie. Return the subtree for the value regardless of whether it is a new value or not.""" @@ -924,12 +925,12 @@ def insert_trie( return trie[value] -def insert_strie(strie: Dict[str, Any], trie: Dict[str, Any], value: str) -> None: +def insert_strie(strie: dict[str, Any], trie: dict[str, Any], value: str) -> None: if value not in strie: strie[value] = insert_trie(trie, value) -def get_longest_namespace(trie: Dict[str, Any], value: str) -> Optional[str]: +def get_longest_namespace(trie: dict[str, Any], value: str) -> Optional[str]: for key in trie: if value.startswith(key): out = get_longest_namespace(trie[key], value) diff --git a/rdflib/parser.py b/rdflib/parser.py index 1c652ca21..462076490 100644 --- a/rdflib/parser.py +++ b/rdflib/parser.py @@ -22,10 +22,8 @@ TYPE_CHECKING, Any, BinaryIO, - List, Optional, TextIO, - Tuple, Union, cast, ) @@ -133,7 +131,7 @@ def _init(self): elif isinstance(self.wrapped, TextIOWrapper): inner = self.wrapped.buffer # type error: TextIOWrapper.buffer cannot be a BytesIOWrapper - if isinstance(inner, BytesIOWrapper): # type: ignore[unreachable] + if isinstance(inner, BytesIOWrapper): # type: ignore[unreachable, unused-ignore] raise Exception( "BytesIOWrapper cannot be wrapped in TextIOWrapper, " "then wrapped in another BytesIOWrapper" @@ -489,7 +487,7 @@ class StringInputSource(InputSource): def __init__( self, - value: Union[str, bytes], + value: str | bytes, encoding: str = "utf-8", system_id: Optional[str] = None, ): @@ -520,26 +518,26 @@ class URLInputSource(InputSource): Constructs an RDFLib Parser InputSource from a URL to read it from the Web. """ - links: List[str] + links: list[str] @classmethod - def getallmatchingheaders(cls, message: Message, name) -> List[str]: + def getallmatchingheaders(cls, message: Message, name) -> list[str]: # This is reimplemented here, because the method # getallmatchingheaders from HTTPMessage is broken since Python 3.0 name = name.lower() return [val for key, val in message.items() if key.lower() == name] @classmethod - def get_links(cls, response: addinfourl) -> List[str]: + def get_links(cls, response: addinfourl) -> list[str]: linkslines = cls.getallmatchingheaders(response.headers, "Link") - retarray: List[str] = [] + retarray: list[str] = [] for linksline in linkslines: links = [linkstr.strip() for linkstr in linksline.split(",")] for link in links: retarray.append(link) return retarray - def get_alternates(self, type_: Optional[str] = None) -> List[str]: + def get_alternates(self, type_: Optional[str] = None) -> list[str]: typestr: Optional[str] = f'type="{type_}"' if type_ else None relstr = 'rel="alternate"' alts = [] @@ -777,7 +775,7 @@ def _create_input_source_from_location( format: Optional[str], input_source: Optional[InputSource], location: str, -) -> Tuple[URIRef, bool, Optional[Union[BinaryIO, TextIO]], Optional[InputSource]]: +) -> tuple[URIRef, bool, Optional[Union[BinaryIO, TextIO]], Optional[InputSource]]: # Fix for Windows problem https://github.com/RDFLib/rdflib/issues/145 and # https://github.com/RDFLib/rdflib/issues/1430 # NOTE: using pathlib.Path.exists on a URL fails on windows as it is not a diff --git a/rdflib/paths.py b/rdflib/paths.py index 3692bad45..4cb1e989c 100644 --- a/rdflib/paths.py +++ b/rdflib/paths.py @@ -185,26 +185,23 @@ import warnings from abc import ABC, abstractmethod from functools import total_ordering -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Generator, - Iterator, - List, - Optional, - Set, - Tuple, - Union, -) +from typing import TYPE_CHECKING, Any, Optional from rdflib.term import Node, URIRef if TYPE_CHECKING: + from collections.abc import Callable, Generator, Iterator + + from typing_extensions import TypeAlias + from rdflib._type_checking import _MulPathMod from rdflib.graph import Graph, _ObjectType, _PredicateType, _SubjectType from rdflib.namespace import NamespaceManager + SubjectType: TypeAlias = _SubjectType + PredicateType: TypeAlias = _PredicateType + ObjectType: TypeAlias = _ObjectType + # property paths @@ -214,7 +211,7 @@ def _n3( - arg: Union[URIRef, Path], namespace_manager: Optional[NamespaceManager] = None + arg: URIRef | Path, namespace_manager: Optional[NamespaceManager] = None ) -> str: if isinstance(arg, (SequencePath, AlternativePath)) and len(arg.args) > 1: return "(%s)" % arg.n3(namespace_manager) @@ -223,19 +220,19 @@ def _n3( @total_ordering class Path(ABC): - __or__: Callable[[Path, Union[URIRef, Path]], AlternativePath] + __or__: Callable[[Path, URIRef | Path], AlternativePath] __invert__: Callable[[Path], InvPath] __neg__: Callable[[Path], NegatedPath] - __truediv__: Callable[[Path, Union[URIRef, Path]], SequencePath] + __truediv__: Callable[[Path, URIRef | Path], SequencePath] __mul__: Callable[[Path, str], MulPath] @abstractmethod def eval( self, graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Iterator[Tuple[_SubjectType, _ObjectType]]: ... + subj: Optional[SubjectType] = None, + obj: Optional[ObjectType] = None, + ) -> Iterator[tuple[SubjectType, ObjectType]]: ... @abstractmethod def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: ... @@ -255,15 +252,15 @@ def __lt__(self, other: Any) -> bool: class InvPath(Path): - def __init__(self, arg: Union[Path, URIRef]): + def __init__(self, arg: Path | URIRef): self.arg = arg def eval( self, graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_ObjectType, _SubjectType], None, None]: + subj: Optional[SubjectType] = None, + obj: Optional[ObjectType] = None, + ) -> Generator[tuple[ObjectType, SubjectType], None, None]: for s, o in eval_path(graph, (obj, self.arg, subj)): yield o, s @@ -275,8 +272,8 @@ def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: class SequencePath(Path): - def __init__(self, *args: Union[Path, URIRef]): - self.args: List[Union[Path, URIRef]] = [] + def __init__(self, *args: Path | URIRef): + self.args: list[Path | URIRef] = [] for a in args: if isinstance(a, SequencePath): self.args += a.args @@ -286,14 +283,14 @@ def __init__(self, *args: Union[Path, URIRef]): def eval( self, graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + subj: Optional[SubjectType] = None, + obj: Optional[ObjectType] = None, + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: def _eval_seq( - paths: List[Union[Path, URIRef]], - subj: Optional[_SubjectType], - obj: Optional[_ObjectType], - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + paths: list[Path | URIRef], + subj: Optional[SubjectType], + obj: Optional[ObjectType], + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: if paths[1:]: for s, o in eval_path(graph, (subj, paths[0], None)): for r in _eval_seq(paths[1:], o, obj): @@ -304,10 +301,10 @@ def _eval_seq( yield s, o def _eval_seq_bw( - paths: List[Union[Path, URIRef]], - subj: Optional[_SubjectType], - obj: _ObjectType, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + paths: list[Path | URIRef], + subj: Optional[SubjectType], + obj: ObjectType, + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: if paths[:-1]: for s, o in eval_path(graph, (None, paths[-1], obj)): for r in _eval_seq(paths[:-1], subj, s): @@ -332,8 +329,8 @@ def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: class AlternativePath(Path): - def __init__(self, *args: Union[Path, URIRef]): - self.args: List[Union[Path, URIRef]] = [] + def __init__(self, *args: Path | URIRef): + self.args: list[Path | URIRef] = [] for a in args: if isinstance(a, AlternativePath): self.args += a.args @@ -343,9 +340,9 @@ def __init__(self, *args: Union[Path, URIRef]): def eval( self, graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + subj: Optional[SubjectType] = None, + obj: Optional[ObjectType] = None, + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: for x in self.args: for y in eval_path(graph, (subj, x, obj)): yield y @@ -358,7 +355,7 @@ def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: class MulPath(Path): - def __init__(self, path: Union[Path, URIRef], mod: _MulPathMod): + def __init__(self, path: Path | URIRef, mod: _MulPathMod): self.path = path self.mod = mod @@ -377,10 +374,10 @@ def __init__(self, path: Union[Path, URIRef], mod: _MulPathMod): def eval( self, graph: Graph, - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, + subj: Optional[SubjectType] = None, + obj: Optional[ObjectType] = None, first: bool = True, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: if self.zero and first: if subj and obj: if subj == obj: @@ -391,45 +388,39 @@ def eval( yield obj, obj def _fwd( - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - seen: Optional[Set[_SubjectType]] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add" - # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node" - seen.add(subj) # type: ignore[union-attr, arg-type] + subj: SubjectType, + obj: Optional[ObjectType], + seen: set[SubjectType], + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: + seen.add(subj) for s, o in eval_path(graph, (subj, self.path, None)): if not obj or o == obj: yield s, o if self.more: - # type error: Unsupported right operand type for in ("Optional[Set[Node]]") - if o in seen: # type: ignore[operator] + if o in seen: continue for s2, o2 in _fwd(o, obj, seen): yield s, o2 def _bwd( - subj: Optional[_SubjectType] = None, - obj: Optional[_ObjectType] = None, - seen: Optional[Set[_ObjectType]] = None, - ) -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: - # type error: Item "None" of "Optional[Set[Node]]" has no attribute "add" - # type error: Argument 1 to "add" of "set" has incompatible type "Optional[Node]"; expected "Node" - seen.add(obj) # type: ignore[union-attr, arg-type] + subj: Optional[SubjectType], + obj: ObjectType, + seen: set[ObjectType], + ) -> Generator[tuple[SubjectType, ObjectType], None, None]: + seen.add(obj) for s, o in eval_path(graph, (None, self.path, obj)): if not subj or subj == s: yield s, o if self.more: - # type error: Unsupported right operand type for in ("Optional[Set[Node]]") - if s in seen: # type: ignore[operator] + if s in seen: continue for s2, o2 in _bwd(None, s, seen): yield s2, o - def _all_fwd_paths() -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: + def _all_fwd_paths() -> Generator[tuple[SubjectType, ObjectType], None, None]: if self.zero: seen1 = set() # According to the spec, ALL nodes are possible solutions @@ -458,12 +449,12 @@ def _all_fwd_paths() -> Generator[Tuple[_SubjectType, _ObjectType], None, None]: yield s1, o1 done = set() # the spec does, by defn, not allow duplicates - if subj: + if subj is not None: for x in _fwd(subj, obj, set()): if x not in done: done.add(x) yield x - elif obj: + elif obj is not None: for x in _bwd(subj, obj, set()): if x not in done: done.add(x) @@ -482,8 +473,8 @@ def n3(self, namespace_manager: Optional[NamespaceManager] = None) -> str: class NegatedPath(Path): - def __init__(self, arg: Union[AlternativePath, InvPath, URIRef]): - self.args: List[Union[URIRef, Path]] + def __init__(self, arg: AlternativePath | InvPath | URIRef): + self.args: list[URIRef | Path] if isinstance(arg, (URIRef, InvPath)): self.args = [arg] elif isinstance(arg, AlternativePath): @@ -519,7 +510,7 @@ class PathList(list): pass -def path_alternative(self: Union[URIRef, Path], other: Union[URIRef, Path]): +def path_alternative(self: URIRef | Path, other: URIRef | Path): """ alternative path """ @@ -528,7 +519,7 @@ def path_alternative(self: Union[URIRef, Path], other: Union[URIRef, Path]): return AlternativePath(self, other) -def path_sequence(self: Union[URIRef, Path], other: Union[URIRef, Path]): +def path_sequence(self: URIRef | Path, other: URIRef | Path): """ sequence path """ @@ -539,12 +530,12 @@ def path_sequence(self: Union[URIRef, Path], other: Union[URIRef, Path]): def evalPath( # noqa: N802 graph: Graph, - t: Tuple[ - Optional[_SubjectType], - Union[None, Path, _PredicateType], - Optional[_ObjectType], + t: tuple[ + Optional[SubjectType], + Optional[Path | PredicateType], + Optional[ObjectType], ], -) -> Iterator[Tuple[_SubjectType, _ObjectType]]: +) -> Iterator[tuple[SubjectType, ObjectType]]: warnings.warn( DeprecationWarning( "rdflib.path.evalPath() is deprecated, use the (snake-cased) eval_path(). " @@ -557,30 +548,30 @@ def evalPath( # noqa: N802 def eval_path( graph: Graph, - t: Tuple[ - Optional[_SubjectType], - Union[None, Path, _PredicateType], - Optional[_ObjectType], + t: tuple[ + Optional[SubjectType], + Optional[Path | PredicateType], + Optional[ObjectType], ], -) -> Iterator[Tuple[_SubjectType, _ObjectType]]: +) -> Iterator[tuple[SubjectType, ObjectType]]: return ((s, o) for s, p, o in graph.triples(t)) -def mul_path(p: Union[URIRef, Path], mul: _MulPathMod) -> MulPath: +def mul_path(p: URIRef | Path, mul: _MulPathMod) -> MulPath: """ cardinality path """ return MulPath(p, mul) -def inv_path(p: Union[URIRef, Path]) -> InvPath: +def inv_path(p: URIRef | Path) -> InvPath: """ inverse path """ return InvPath(p) -def neg_path(p: Union[URIRef, AlternativePath, InvPath]) -> NegatedPath: +def neg_path(p: URIRef | AlternativePath | InvPath) -> NegatedPath: """ negated path """ @@ -605,7 +596,7 @@ def neg_path(p: Union[URIRef, AlternativePath, InvPath]) -> NegatedPath: Path.__invert__ = inv_path # type error: Incompatible types in assignment (expression has type "Callable[[Union[URIRef, AlternativePath, InvPath]], NegatedPath]", variable has type "Callable[[Path], NegatedPath]") Path.__neg__ = neg_path # type: ignore[assignment] - # type error: Incompatible types in assignment (expression has type "Callable[[Union[URIRef, Path], Literal['*', '+', '?']], MulPath]", variable has type "Callable[[Path, str], MulPath]") + # type error: Incompatible types in assignment (expression has type "Callable[[URIRef|Path, Literal['*', '+', '?']], MulPath]", variable has type "Callable[[Path, str], MulPath]") Path.__mul__ = mul_path # type: ignore[assignment] Path.__or__ = path_alternative Path.__truediv__ = path_sequence diff --git a/rdflib/plugin.py b/rdflib/plugin.py index 23699e68d..aa6203e40 100644 --- a/rdflib/plugin.py +++ b/rdflib/plugin.py @@ -27,16 +27,13 @@ from __future__ import annotations +from collections.abc import Iterator from importlib.metadata import EntryPoint, entry_points from typing import ( TYPE_CHECKING, Any, - Dict, Generic, - Iterator, Optional, - Tuple, - Type, TypeVar, overload, ) @@ -75,7 +72,7 @@ "rdf.plugins.updateprocessor": UpdateProcessor, } -_plugins: Dict[Tuple[str, Type[Any]], Plugin] = {} +_plugins: dict[tuple[str, type[Any]], Plugin] = {} class PluginException(Error): # noqa: N818 @@ -88,15 +85,15 @@ class PluginException(Error): # noqa: N818 class Plugin(Generic[PluginT]): def __init__( - self, name: str, kind: Type[PluginT], module_path: str, class_name: str + self, name: str, kind: type[PluginT], module_path: str, class_name: str ): self.name = name self.kind = kind self.module_path = module_path self.class_name = class_name - self._class: Optional[Type[PluginT]] = None + self._class: Optional[type[PluginT]] = None - def getClass(self) -> Type[PluginT]: # noqa: N802 + def getClass(self) -> type[PluginT]: # noqa: N802 if self._class is None: module = __import__(self.module_path, globals(), locals(), [""]) self._class = getattr(module, self.class_name) @@ -104,19 +101,19 @@ def getClass(self) -> Type[PluginT]: # noqa: N802 class PKGPlugin(Plugin[PluginT]): - def __init__(self, name: str, kind: Type[PluginT], ep: EntryPoint): + def __init__(self, name: str, kind: type[PluginT], ep: EntryPoint): self.name = name self.kind = kind self.ep = ep - self._class: Optional[Type[PluginT]] = None + self._class: Optional[type[PluginT]] = None - def getClass(self) -> Type[PluginT]: # noqa: N802 + def getClass(self) -> type[PluginT]: # noqa: N802 if self._class is None: self._class = self.ep.load() return self._class -def register(name: str, kind: Type[Any], module_path, class_name): +def register(name: str, kind: type[Any], module_path, class_name): """ Register the plugin for (name, kind). The module_path and class_name should be the path to a plugin class. @@ -125,7 +122,7 @@ def register(name: str, kind: Type[Any], module_path, class_name): _plugins[(name, kind)] = p -def get(name: str, kind: Type[PluginT]) -> Type[PluginT]: +def get(name: str, kind: type[PluginT]) -> type[PluginT]: """ Return the class for the specified (name, kind). Raises a PluginException if unable to do so. @@ -153,7 +150,7 @@ def get(name: str, kind: Type[PluginT]) -> Type[PluginT]: @overload def plugins( - name: Optional[str] = ..., kind: Type[PluginT] = ... + name: Optional[str] = ..., kind: type[PluginT] = ... ) -> Iterator[Plugin[PluginT]]: ... @@ -162,7 +159,7 @@ def plugins(name: Optional[str] = ..., kind: None = ...) -> Iterator[Plugin]: .. def plugins( - name: Optional[str] = None, kind: Optional[Type[PluginT]] = None + name: Optional[str] = None, kind: Optional[type[PluginT]] = None ) -> Iterator[Plugin[PluginT]]: """ A generator of the plugins. diff --git a/rdflib/plugins/parsers/hext.py b/rdflib/plugins/parsers/hext.py index 99aa47698..9753b38db 100644 --- a/rdflib/plugins/parsers/hext.py +++ b/rdflib/plugins/parsers/hext.py @@ -9,7 +9,7 @@ import json import warnings from io import TextIOWrapper -from typing import TYPE_CHECKING, Any, BinaryIO, List, Optional, TextIO, Union +from typing import TYPE_CHECKING, Any, BinaryIO, Optional, TextIO, Union from rdflib.graph import ConjunctiveGraph, Dataset, Graph from rdflib.parser import InputSource, Parser @@ -40,7 +40,7 @@ def __init__(self): self.skolemize = False def _parse_hextuple( - self, ds: Union[Dataset, ConjunctiveGraph], tup: List[Union[str, None]] + self, ds: Union[Dataset, ConjunctiveGraph], tup: list[Union[str, None]] ) -> None: # all values check # subject, predicate, value, datatype cannot be None @@ -156,7 +156,7 @@ def parse(self, source: InputSource, graph: Graph, skolemize: bool = False, **kw use_stream = TextIOWrapper(binary_stream, encoding="utf-8") loads = json.loads - for line in use_stream: # type: Union[str, bytes] + for line in use_stream: # type: str|bytes if len(line) == 0 or line.isspace(): # Skipping empty lines because this is what was being done before for the first and last lines, albeit in an rather indirect way. # The result is that we accept input that would otherwise be invalid. @@ -165,7 +165,7 @@ def parse(self, source: InputSource, graph: Graph, skolemize: bool = False, **kw # this complex handing is because the 'value' component is # allowed to be "" but not None # all other "" values are treated as None - raw_line: List[str] = loads(line) + raw_line: list[str] = loads(line) hex_tuple_line = [x if x != "" else None for x in raw_line] if raw_line[2] == "": hex_tuple_line[2] = "" diff --git a/rdflib/plugins/parsers/jsonld.py b/rdflib/plugins/parsers/jsonld.py index 295a97126..10ce4d04c 100644 --- a/rdflib/plugins/parsers/jsonld.py +++ b/rdflib/plugins/parsers/jsonld.py @@ -35,13 +35,14 @@ from __future__ import annotations import warnings -from typing import TYPE_CHECKING, Any, Dict, Iterable, List, Optional, Union +from collections.abc import Iterable +from typing import TYPE_CHECKING, Any, Optional, Union import rdflib.parser from rdflib.graph import ConjunctiveGraph, Graph from rdflib.namespace import RDF, XSD from rdflib.parser import InputSource, URLInputSource -from rdflib.term import BNode, IdentifiedNode, Literal, Node, URIRef +from rdflib.term import BNode, IdentifiedNode, Literal, URIRef from ..shared.jsonld.context import UNDEF, Context, Term from ..shared.jsonld.keys import ( @@ -70,6 +71,9 @@ source_to_json, ) +if TYPE_CHECKING: + from rdflib.graph import _ObjectType + __all__ = ["JsonLDParser", "to_rdf"] TYPE_TERM = Term(str(RDF.type), TYPE, VOCAB) # type: ignore[call-arg] @@ -91,8 +95,8 @@ def parse( base: Optional[str] = None, context: Optional[ Union[ - List[Union[Dict[str, Any], str, None]], - Dict[str, Any], + list[Union[dict[str, Any], str, None]], + dict[str, Any], str, ] ] = None, @@ -185,8 +189,8 @@ def to_rdf( base: Optional[str] = None, context_data: Optional[ Union[ - List[Union[Dict[str, Any], str, None]], - Dict[str, Any], + list[Union[dict[str, Any], str, None]], + dict[str, Any], str, ] ] = None, @@ -224,7 +228,7 @@ def __init__( def parse(self, data: Any, context: Context, dataset: Graph) -> Graph: topcontext = False - resources: Union[Dict[str, Any], List[Any]] + resources: Union[dict[str, Any], list[Any]] if isinstance(data, list): resources = data elif isinstance(data, dict): @@ -258,7 +262,7 @@ def _add_to_graph( context: Context, node: Any, topcontext: bool = False, - ) -> Optional[Node]: + ) -> Optional[IdentifiedNode]: if not isinstance(node, dict) or context.get_value(node): # type error: Return value expected return # type: ignore[return-value] @@ -280,12 +284,13 @@ def _add_to_graph( if nested_id is not None and len(nested_id) > 0: id_val = nested_id + subj: Optional[IdentifiedNode] + if isinstance(id_val, str): subj = self._to_rdf_id(context, id_val) else: - subj = BNode() - if self.skolemize: - subj = subj.skolemize() + _bn = BNode() + subj = _bn if not self.skolemize else _bn.skolemize() if subj is None: return None @@ -315,7 +320,7 @@ def _add_to_graph( return subj # type error: Missing return statement - def _get_nested_id(self, context: Context, node: Dict[str, Any]) -> Optional[str]: # type: ignore[return] + def _get_nested_id(self, context: Context, node: dict[str, Any]) -> Optional[str]: # type: ignore[return] for key, obj in node.items(): if context.version >= 1.1 and key in context.get_keys(NEST): term = context.terms.get(key) @@ -339,7 +344,7 @@ def _key_to_graph( dataset: Graph, graph: Graph, context: Context, - subj: Node, + subj: IdentifiedNode, key: str, obj: Any, reverse: bool = False, @@ -369,8 +374,7 @@ def _key_to_graph( if dataset.context_aware and not no_id: if TYPE_CHECKING: assert isinstance(dataset, ConjunctiveGraph) - # type error: Argument 1 to "get_context" of "ConjunctiveGraph" has incompatible type "Node"; expected "Union[IdentifiedNode, str, None]" - subgraph = dataset.get_context(subj) # type: ignore[arg-type] + subgraph = dataset.get_context(subj) else: subgraph = graph for onode in obj_nodes: @@ -409,7 +413,7 @@ def _key_to_graph( context = context.get_context_for_term(term) # Flatten deep nested lists - def flatten(n: Iterable[Any]) -> List[Any]: + def flatten(n: Iterable[Any]) -> list[Any]: flattened = [] for obj in n: if isinstance(obj, dict): @@ -451,8 +455,8 @@ def flatten(n: Iterable[Any]) -> List[Any]: graph.add((subj, pred, obj)) def _parse_container( - self, context: Context, term: Term, obj: Dict[str, Any] - ) -> List[Any]: + self, context: Context, term: Term, obj: dict[str, Any] + ) -> list[Any]: if LANG in term.container: obj_nodes = [] for lang, values in obj.items(): @@ -531,7 +535,7 @@ def _parse_container( return [obj] @staticmethod - def _add_type(context: Context, o: Dict[str, Any], k: str) -> Dict[str, Any]: + def _add_type(context: Context, o: dict[str, Any], k: str) -> dict[str, Any]: otype = context.get_type(o) or [] if otype and not isinstance(otype, list): otype = [otype] @@ -547,7 +551,7 @@ def _to_object( term: Optional[Term], node: Any, inlist: bool = False, - ) -> Optional[Node]: + ) -> Optional[_ObjectType]: if isinstance(node, tuple): value, lang = node if value is None: @@ -682,7 +686,7 @@ def _add_list( return RDF.nil @staticmethod - def _to_typed_json_value(value: Any) -> Dict[str, str]: + def _to_typed_json_value(value: Any) -> dict[str, str]: if _HAS_ORJSON: val_string: str = orjson.dumps( value, @@ -698,7 +702,7 @@ def _to_typed_json_value(value: Any) -> Dict[str, str]: } @classmethod - def _expand_nested_list(cls, obj_nodes: List[Any]) -> Dict[str, List[Any]]: + def _expand_nested_list(cls, obj_nodes: list[Any]) -> dict[str, list[Any]]: result = [ cls._expand_nested_list(o) if isinstance(o, list) else o for o in obj_nodes ] diff --git a/rdflib/plugins/parsers/notation3.py b/rdflib/plugins/parsers/notation3.py index da71405e0..92b2e5548 100755 --- a/rdflib/plugins/parsers/notation3.py +++ b/rdflib/plugins/parsers/notation3.py @@ -33,25 +33,18 @@ import os import re import sys - -# importing typing for `typing.List` because `List`` is used for something else -import typing from decimal import Decimal +from re import Pattern from typing import ( IO, TYPE_CHECKING, Any, - Callable, - Dict, - Match, - MutableSequence, NoReturn, Optional, - Pattern, - Set, - Tuple, TypeVar, Union, + cast, + overload, ) from uuid import uuid4 @@ -88,12 +81,16 @@ from rdflib.parser import Parser if TYPE_CHECKING: + from collections.abc import Callable, MutableSequence + from re import Match # Replaces typing.Match in Python 3.9+ + + from rdflib.graph import _ObjectType, _PredicateType, _SubjectType from rdflib.parser import InputSource _AnyT = TypeVar("_AnyT") -def splitFragP(uriref: str, punc: int = 0) -> Tuple[str, str]: +def splitFragP(uriref: str, punc: int = 0) -> tuple[str, str]: """split a URI reference before the fragment Punctuation is kept. @@ -410,10 +407,10 @@ def __init__( self._genPrefix = genPrefix self.keywords = ["a", "this", "bind", "has", "is", "of", "true", "false"] self.keywordsSet = 0 # Then only can others be considered qnames - self._anonymousNodes: Dict[str, BNode] = {} + self._anonymousNodes: dict[str, BNode] = {} # Dict of anon nodes already declared ln: Term - self._variables: Dict[str, Variable] = {} - self._parentVariables: Dict[str, Variable] = {} + self._variables: dict[str, Variable] = {} + self._parentVariables: dict[str, Variable] = {} self._reason = why # Why the parser was asked to parse this self.turtle = turtle # raise exception when encountering N3 extensions @@ -478,14 +475,14 @@ def formula(self) -> Optional[Formula]: def loadStream(self, stream: Union[IO[str], IO[bytes]]) -> Optional[Formula]: return self.loadBuf(stream.read()) # Not ideal - def loadBuf(self, buf: Union[str, bytes]) -> Optional[Formula]: + def loadBuf(self, buf: str | bytes) -> Optional[Formula]: """Parses a buffer and returns its top level formula""" self.startDoc() self.feed(buf) return self.endDoc() # self._formula - def feed(self, octets: Union[str, bytes]) -> None: + def feed(self, octets: str | bytes) -> None: """Feed an octet stream to the parser if BadSyntax is raised, the string @@ -582,7 +579,7 @@ def directive(self, argstr: str, i: int) -> int: j = self.skipSpace(argstr, i) if j < 0: return j # eof - res: typing.List[str] = [] + res: list[str] = [] j = self.tok("bind", argstr, i) # implied "#". Obsolete. if j > 0: @@ -631,7 +628,7 @@ def directive(self, argstr: str, i: int) -> int: j = self.tok("prefix", argstr, i, colon=True) # no implied "#" if j >= 0: - t: typing.List[Union[Identifier, Tuple[str, str]]] = [] + t: list[Union[Identifier, tuple[str, str]]] = [] i = self.qname(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected qname after @prefix") @@ -690,7 +687,7 @@ def sparqlDirective(self, argstr: str, i: int) -> int: j = self.sparqlTok("PREFIX", argstr, i) if j >= 0: - t: typing.List[Any] = [] + t: list[Any] = [] i = self.qname(argstr, j, t) if i < 0: self.BadSyntax(argstr, j, "expected qname after @prefix") @@ -747,7 +744,7 @@ def bind(self, qn: str, uri: bytes) -> None: else: self._store.bind(qn, uri) - def setKeywords(self, k: Optional[typing.List[str]]) -> None: + def setKeywords(self, k: Optional[list[str]]) -> None: """Takes a list of strings""" if k is None: self.keywordsSet = 0 @@ -770,7 +767,7 @@ def makeStatement(self, quadruple) -> None: self._store.makeStatement(quadruple, why=self._reason2) def statement(self, argstr: str, i: int) -> int: - r: typing.List[Any] = [] + r: list[Any] = [] i = self.object(argstr, i, r) # Allow literal for subject - extends RDF if i < 0: return i @@ -798,7 +795,7 @@ def verb(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: if j < 0: return j # eof - r: typing.List[Any] = [] + r: list[Any] = [] j = self.tok("has", argstr, i) if j >= 0: @@ -940,7 +937,7 @@ def node( argstr, j, "Found '[=' or '[ =' when in turtle mode." ) i = j + 1 - objs: typing.List[Node] = [] + objs: list[Node] = [] j = self.objectList(argstr, i, objs) if j >= 0: subj = objs[0] @@ -1001,7 +998,7 @@ def node( else: first_run = False - item: typing.List[Any] = [] + item: list[Any] = [] j = self.item(argstr, i, item) # @@@@@ should be path, was object if j < 0: self.BadSyntax(argstr, i, "expected item in set or '$}'") @@ -1053,7 +1050,7 @@ def node( if ch == "(": thing_type: Callable[ - [typing.List[Any], Optional[Formula]], Union[Set[Any], IdentifiedNode] + [list[Any], Optional[Formula]], Union[set[Any], IdentifiedNode] ] thing_type = self._store.newList ch2 = argstr[i + 1] @@ -1124,19 +1121,19 @@ def property_list(self, argstr: str, i: int, subj: Node) -> int: if self.turtle: self.BadSyntax(argstr, j, "Found in ':-' in Turtle mode") i = j + 2 - res: typing.List[Any] = [] + res: list[Any] = [] j = self.node(argstr, i, res, subj) if j < 0: self.BadSyntax(argstr, i, "bad {} or () or [] node after :- ") i = j continue i = j - v: typing.List[Any] = [] + v: list[Any] = [] j = self.verb(argstr, i, v) if j <= 0: return i # void but valid - objs: typing.List[Any] = [] + objs: list[Any] = [] i = self.objectList(argstr, j, objs) if i < 0: self.BadSyntax(argstr, j, "objectList expected") @@ -1220,7 +1217,7 @@ def uri_ref2(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: NS and local name is now used though I prefer inserting a '#' to make the namesapces look more like what XML folks expect. """ - qn: typing.List[Any] = [] + qn: list[Any] = [] j = self.qname(argstr, i, qn) if j >= 0: pfx, ln = qn[0] @@ -1247,7 +1244,7 @@ def uri_ref2(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: return -1 if argstr[i] == "?": - v: typing.List[Any] = [] + v: list[Any] = [] j = self.variable(argstr, i, v) if j > 0: # Forget variables as a class, only in context. res.append(v[0]) @@ -1374,7 +1371,7 @@ def qname( self, argstr: str, i: int, - res: MutableSequence[Union[Identifier, Tuple[str, str]]], + res: MutableSequence[Union[Identifier, tuple[str, str]]], ) -> int: """ xyz:def -> ('xyz', 'def') @@ -1571,7 +1568,7 @@ def nodeOrLiteral(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: lang = argstr[j + 1 : i] j = i if argstr[j : j + 2] == "^^": - res2: typing.List[Any] = [] + res2: list[Any] = [] j = self.uri_ref2(argstr, j + 2, res2) # Read datatype URI dt = res2[0] res.append(self._store.newLiteral(s, dt, lang)) @@ -1579,13 +1576,13 @@ def nodeOrLiteral(self, argstr: str, i: int, res: MutableSequence[Any]) -> int: else: return -1 - def uriOf(self, sym: Union[Identifier, Tuple[str, str]]) -> str: + def uriOf(self, sym: Union[Identifier, tuple[str, str]]) -> str: if isinstance(sym, tuple): return sym[1] # old system for --pipe # return sym.uriref() # cwm api return sym - def strconst(self, argstr: str, i: int, delim: str) -> Tuple[int, str]: + def strconst(self, argstr: str, i: int, delim: str) -> tuple[int, str]: """parse an N3 string constant delimited by delim. return index, val """ @@ -1704,7 +1701,7 @@ def _unicodeEscape( reg: Pattern[str], n: int, prefix: str, - ) -> Tuple[int, str]: + ) -> tuple[int, str]: if len(argstr) < i + n: raise BadSyntax( self._thisDoc, startline, argstr, i, "unterminated string literal(3)" @@ -1720,10 +1717,10 @@ def _unicodeEscape( "bad string literal hex escape: " + argstr[i : i + n], ) - def uEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]: + def uEscape(self, argstr: str, i: int, startline: int) -> tuple[int, str]: return self._unicodeEscape(argstr, i, startline, unicodeEscape4, 4, "u") - def UEscape(self, argstr: str, i: int, startline: int) -> Tuple[int, str]: + def UEscape(self, argstr: str, i: int, startline: int) -> tuple[int, str]: return self._unicodeEscape(argstr, i, startline, unicodeEscape8, 8, "U") def BadSyntax(self, argstr: str, i: int, msg: str) -> NoReturn: @@ -1781,8 +1778,8 @@ def __init__(self, parent: Graph): self.counter = 0 Formula.number += 1 self.number = Formula.number - self.existentials: Dict[str, BNode] = {} - self.universals: Dict[str, BNode] = {} + self.existentials: dict[str, BNode] = {} + self.universals: dict[str, BNode] = {} self.quotedgraph = QuotedGraph(store=parent.store, identifier=self.id()) @@ -1858,7 +1855,7 @@ def newLiteral(self, s: str, dt: Optional[URIRef], lang: Optional[str]) -> Liter else: return Literal(s, lang=lang) - def newList(self, n: typing.List[Any], f: Optional[Formula]) -> IdentifiedNode: + def newList(self, n: list[Any], f: Optional[Formula]) -> IdentifiedNode: nil = self.newSymbol("http://www.w3.org/1999/02/22-rdf-syntax-ns#nil") if not n: return nil @@ -1876,7 +1873,7 @@ def newList(self, n: typing.List[Any], f: Optional[Formula]) -> IdentifiedNode: self.makeStatement((f, rest, a, nil)) return af - def newSet(self, *args: _AnyT) -> Set[_AnyT]: + def newSet(self, *args: _AnyT) -> set[_AnyT]: return set(args) def setDefaultNamespace(self, *args: bytes) -> str: @@ -1884,7 +1881,7 @@ def setDefaultNamespace(self, *args: bytes) -> str: def makeStatement( self, - quadruple: Tuple[Optional[Union[Formula, Graph]], Node, Node, Node], + quadruple: tuple[Optional[Union[Formula, Graph]], Node, Node, Node], why: Optional[Any] = None, ) -> None: f, p, s, o = quadruple @@ -1893,26 +1890,44 @@ def makeStatement( raise ParserError("Formula used as predicate") # type error: Argument 1 to "normalise" of "RDFSink" has incompatible type "Union[Formula, Graph, None]"; expected "Optional[Formula]" - s = self.normalise(f, s) # type: ignore[arg-type] - p = self.normalise(f, p) # type: ignore[arg-type] - o = self.normalise(f, o) # type: ignore[arg-type] + s_normal: _SubjectType = cast("_SubjectType", self.normalise(f, s)) + p_normal: _PredicateType = cast("_PredicateType", self.normalise(f, p)) + o_normal: _ObjectType = cast("_ObjectType", self.normalise(f, o)) if f == self.rootFormula: # print s, p, o, '.' - self.graph.add((s, p, o)) + self.graph.add((s_normal, p_normal, o_normal)) elif isinstance(f, Formula): - f.quotedgraph.add((s, p, o)) + f.quotedgraph.add((s_normal, p_normal, o_normal)) else: # type error: Item "None" of "Optional[Graph]" has no attribute "add" - f.add((s, p, o)) # type: ignore[union-attr] + f.add((s_normal, p_normal, o_normal)) # type: ignore[union-attr] # return str(quadruple) + @overload + def normalise(self, f: Optional[Formula | Graph], n: tuple[int, str]) -> URIRef: ... + + @overload + def normalise(self, f: Optional[Formula | Graph], n: bool) -> Literal: ... + + @overload + def normalise(self, f: Optional[Formula | Graph], n: int) -> Literal: ... + + @overload + def normalise(self, f: Optional[Formula | Graph], n: Decimal) -> Literal: ... + + @overload + def normalise(self, f: Optional[Formula | Graph], n: float) -> Literal: ... + + @overload + def normalise(self, f: Optional[Formula | Graph], n: Node) -> Node: ... + def normalise( self, - f: Optional[Formula], - n: Union[Tuple[int, str], bool, int, Decimal, float, _AnyT], - ) -> Union[URIRef, Literal, BNode, _AnyT]: + f: Optional[Formula | Graph], + n: Union[tuple[int, str], bool, int, Decimal, float, Node, _AnyT], + ) -> Union[URIRef, Literal, BNode, Node, _AnyT]: if isinstance(n, tuple): return URIRef(str(n[1])) diff --git a/rdflib/plugins/parsers/nquads.py b/rdflib/plugins/parsers/nquads.py index 60b793b65..b197d3430 100644 --- a/rdflib/plugins/parsers/nquads.py +++ b/rdflib/plugins/parsers/nquads.py @@ -26,7 +26,8 @@ from __future__ import annotations from codecs import getreader -from typing import Any, MutableMapping, Optional +from collections.abc import MutableMapping +from typing import Any, Optional from rdflib.exceptions import ParserError as ParseError from rdflib.graph import ConjunctiveGraph, Dataset, Graph diff --git a/rdflib/plugins/parsers/ntriples.py b/rdflib/plugins/parsers/ntriples.py index 933e99f3f..6f73dda5d 100644 --- a/rdflib/plugins/parsers/ntriples.py +++ b/rdflib/plugins/parsers/ntriples.py @@ -8,15 +8,14 @@ import codecs import re +from collections.abc import MutableMapping from io import BytesIO, StringIO, TextIOBase +from re import Match, Pattern from typing import ( IO, TYPE_CHECKING, Any, - Match, - MutableMapping, Optional, - Pattern, TextIO, Union, ) diff --git a/rdflib/plugins/parsers/patch.py b/rdflib/plugins/parsers/patch.py index 5e8f12d1f..0c0b87d64 100644 --- a/rdflib/plugins/parsers/patch.py +++ b/rdflib/plugins/parsers/patch.py @@ -1,8 +1,9 @@ from __future__ import annotations from codecs import getreader +from collections.abc import MutableMapping from enum import Enum -from typing import TYPE_CHECKING, Any, MutableMapping, Optional, Union +from typing import TYPE_CHECKING, Any, Optional, Union from rdflib.exceptions import ParserError as ParseError from rdflib.graph import Dataset diff --git a/rdflib/plugins/parsers/rdfxml.py b/rdflib/plugins/parsers/rdfxml.py index 54fc69567..72bef1dcf 100644 --- a/rdflib/plugins/parsers/rdfxml.py +++ b/rdflib/plugins/parsers/rdfxml.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Dict, List, NoReturn, Optional, Tuple +from typing import TYPE_CHECKING, Any, NoReturn, Optional from urllib.parse import urldefrag, urljoin from xml.sax import handler, make_parser, xmlreader from xml.sax.handler import ErrorHandler @@ -15,7 +15,7 @@ from rdflib.namespace import RDF, is_ncname from rdflib.parser import InputSource, Parser from rdflib.plugins.parsers.RDFVOC import RDFVOC -from rdflib.term import BNode, Identifier, Literal, URIRef +from rdflib.term import BNode, IdentifiedNode, Literal, URIRef if TYPE_CHECKING: # from xml.sax.expatreader import ExpatLocator @@ -146,16 +146,16 @@ def reset(self) -> None: document_element = ElementHandler() document_element.start = self.document_element_start document_element.end = lambda name, qname: None - self.stack: List[Optional[ElementHandler]] = [ + self.stack: list[Optional[ElementHandler]] = [ None, document_element, ] - self.ids: Dict[str, int] = {} # remember IDs we have already seen - self.bnode: Dict[str, Identifier] = {} - self._ns_contexts: List[Dict[str, Optional[str]]] = [ + self.ids: dict[str, int] = {} # remember IDs we have already seen + self.bnode: dict[str, IdentifiedNode] = {} + self._ns_contexts: list[dict[str, Optional[str]]] = [ {} ] # contains uri -> prefix dicts - self._current_context: Dict[str, Optional[str]] = self._ns_contexts[-1] + self._current_context: dict[str, Optional[str]] = self._ns_contexts[-1] # ContentHandler methods @@ -175,7 +175,7 @@ def endPrefixMapping(self, prefix: Optional[str]) -> None: del self._ns_contexts[-1] def startElementNS( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl + self, name: tuple[Optional[str], str], qname, attrs: AttributesImpl ) -> None: stack = self.stack stack.append(ElementHandler()) @@ -207,7 +207,7 @@ def startElementNS( current.language = language current.start(name, qname, attrs) - def endElementNS(self, name: Tuple[Optional[str], str], qname) -> None: + def endElementNS(self, name: tuple[Optional[str], str], qname) -> None: self.current.end(name, qname) self.stack.pop() @@ -222,7 +222,7 @@ def ignorableWhitespace(self, content) -> None: def processingInstruction(self, target, data) -> None: pass - def add_reified(self, sid: Identifier, spo: _TripleType): + def add_reified(self, sid: IdentifiedNode, spo: _TripleType): s, p, o = spo self.store.add((sid, RDF.type, RDF.Statement)) self.store.add((sid, RDF.subject, s)) @@ -267,8 +267,8 @@ def absolutize(self, uri: str) -> URIRef: return URIRef(result) def convert( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl - ) -> Tuple[URIRef, Dict[URIRef, str]]: + self, name: tuple[Optional[str], str], qname, attrs: AttributesImpl + ) -> tuple[URIRef, dict[URIRef, str]]: if name[0] is None: # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[Optional[str], str]") name = URIRef(name[1]) # type: ignore[assignment] @@ -291,11 +291,11 @@ def convert( atts[RDFNS[att]] = v # type: ignore[misc, valid-type] else: atts[URIRef(att)] = v - # type error: Incompatible return value type (got "Tuple[Tuple[Optional[str], str], Dict[Any, Any]]", expected "Tuple[URIRef, Dict[URIRef, str]]") + # type error: Incompatible return value type (got "Tuple[Tuple[Optional[str], str], dict[Any, Any]]", expected "Tuple[URIRef, dict[URIRef, str]]") return name, atts # type: ignore[return-value] def document_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl + self, name: tuple[str, str], qname, attrs: AttributesImpl ) -> None: if name[0] and URIRef("".join(name)) == RDFVOC.RDF: # Cheap hack so 2to3 doesn't turn it into __next__ @@ -309,7 +309,7 @@ def document_element_start( # another element will cause error def node_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl + self, name: tuple[str, str], qname, attrs: AttributesImpl ) -> None: # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[str, str]") name, atts = self.convert(name, qname, attrs) # type: ignore[assignment] @@ -391,7 +391,7 @@ def node_element_start( current.subject = subject - def node_element_end(self, name: Tuple[str, str], qname) -> None: + def node_element_end(self, name: tuple[str, str], qname) -> None: # repeat node-elements are only allowed # at at top-level @@ -403,7 +403,7 @@ def node_element_end(self, name: Tuple[str, str], qname) -> None: self.parent.object = self.current.subject def property_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl + self, name: tuple[str, str], qname, attrs: AttributesImpl ) -> None: # type error: Incompatible types in assignment (expression has type "URIRef", variable has type "Tuple[str, str]") name, atts = self.convert(name, qname, attrs) # type: ignore[assignment] @@ -533,7 +533,7 @@ def property_element_char(self, data: str) -> None: if current.data is not None: current.data += data - def property_element_end(self, name: Tuple[str, str], qname) -> None: + def property_element_end(self, name: tuple[str, str], qname) -> None: current = self.current if current.data is not None and current.object is None: literalLang = current.language @@ -552,7 +552,7 @@ def property_element_end(self, name: Tuple[str, str], qname) -> None: ) current.subject = None - def list_node_element_end(self, name: Tuple[str, str], qname) -> None: + def list_node_element_end(self, name: tuple[str, str], qname) -> None: current = self.current if self.parent.list == RDF.nil: list = BNode() @@ -571,7 +571,7 @@ def list_node_element_end(self, name: Tuple[str, str], qname) -> None: self.parent.list = list def literal_element_start( - self, name: Tuple[str, str], qname, attrs: AttributesImpl + self, name: tuple[str, str], qname, attrs: AttributesImpl ) -> None: current = self.current self.next.start = self.literal_element_start @@ -607,7 +607,7 @@ def literal_element_start( def literal_element_char(self, data: str) -> None: self.current.object += escape(data) - def literal_element_end(self, name: Tuple[str, str], qname) -> None: + def literal_element_end(self, name: tuple[str, str], qname) -> None: if name[0]: prefix = self._current_context[name[0]] if prefix: diff --git a/rdflib/plugins/parsers/trig.py b/rdflib/plugins/parsers/trig.py index 9ed6e8bbc..4eb23d57c 100644 --- a/rdflib/plugins/parsers/trig.py +++ b/rdflib/plugins/parsers/trig.py @@ -1,6 +1,7 @@ from __future__ import annotations -from typing import Any, MutableSequence +from collections.abc import MutableSequence +from typing import Any from rdflib.graph import ConjunctiveGraph, Graph from rdflib.parser import InputSource, Parser diff --git a/rdflib/plugins/parsers/trix.py b/rdflib/plugins/parsers/trix.py index 833e18568..9120bc729 100644 --- a/rdflib/plugins/parsers/trix.py +++ b/rdflib/plugins/parsers/trix.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Any, Dict, List, NoReturn, Optional, Tuple +from typing import TYPE_CHECKING, Any, NoReturn, Optional from xml.sax import handler, make_parser from xml.sax.handler import ErrorHandler @@ -38,9 +38,9 @@ def __init__(self, store: Store): self.reset() def reset(self) -> None: - self.bnode: Dict[str, BNode] = {} + self.bnode: dict[str, BNode] = {} self.graph: Optional[Graph] = None - self.triple: Optional[List[Identifier]] = None + self.triple: Optional[list[Identifier]] = None self.state = 0 self.lang = None self.datatype = None @@ -60,7 +60,7 @@ def endPrefixMapping(self, prefix: Optional[str]) -> None: pass def startElementNS( - self, name: Tuple[Optional[str], str], qname, attrs: AttributesImpl + self, name: tuple[Optional[str], str], qname, attrs: AttributesImpl ) -> None: if name[0] != str(TRIXNS): self.error( @@ -150,7 +150,7 @@ def startElementNS( self.chars = "" - def endElementNS(self, name: Tuple[Optional[str], str], qname) -> None: + def endElementNS(self, name: tuple[Optional[str], str], qname) -> None: if TYPE_CHECKING: assert self.triple is not None if name[0] != str(TRIXNS): diff --git a/rdflib/plugins/serializers/hext.py b/rdflib/plugins/serializers/hext.py index 9a8187c76..3f102395b 100644 --- a/rdflib/plugins/serializers/hext.py +++ b/rdflib/plugins/serializers/hext.py @@ -7,7 +7,8 @@ import json import warnings -from typing import IO, Any, Callable, List, Optional, Type, Union, cast +from collections.abc import Callable +from typing import IO, Any, Optional, Union, cast from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, ConjunctiveGraph, Dataset, Graph from rdflib.namespace import RDF, XSD @@ -30,7 +31,7 @@ class HextuplesSerializer(Serializer): Serializes RDF graphs to NTriples format. """ - contexts: List[Union[Graph, IdentifiedNode]] + contexts: list[Union[Graph, IdentifiedNode]] dumps: Callable def __new__(cls, store: Union[Graph, Dataset, ConjunctiveGraph]): @@ -54,7 +55,7 @@ def __new__(cls, store: Union[Graph, Dataset, ConjunctiveGraph]): def __init__(self, store: Union[Graph, Dataset, ConjunctiveGraph]): self.default_context: Optional[Union[Graph, IdentifiedNode]] - self.graph_type: Union[Type[Graph], Type[Dataset], Type[ConjunctiveGraph]] + self.graph_type: Union[type[Graph], type[Dataset], type[ConjunctiveGraph]] if isinstance(store, (Dataset, ConjunctiveGraph)): self.graph_type = ( Dataset if isinstance(store, Dataset) else ConjunctiveGraph @@ -163,7 +164,7 @@ def _hex_line(self, triple, context_str: Union[bytes, str]): language, context_str, ] - outline: Union[str, bytes] + outline: str | bytes if _HAS_ORJSON: outline = orjson.dumps(line_list, option=orjson.OPT_APPEND_NEWLINE) else: diff --git a/rdflib/plugins/serializers/jsonld.py b/rdflib/plugins/serializers/jsonld.py index 15f307edf..ecf43f365 100644 --- a/rdflib/plugins/serializers/jsonld.py +++ b/rdflib/plugins/serializers/jsonld.py @@ -38,17 +38,23 @@ from __future__ import annotations import warnings -from typing import IO, Any, Dict, List, Optional +from typing import IO, TYPE_CHECKING, Any, Optional, Union, cast -from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, Graph, _ObjectType +from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, Graph from rdflib.namespace import RDF, XSD from rdflib.serializer import Serializer -from rdflib.term import BNode, IdentifiedNode, Identifier, Literal, URIRef +from rdflib.term import BNode, IdentifiedNode, Literal, URIRef from ..shared.jsonld.context import UNDEF, Context from ..shared.jsonld.keys import CONTEXT, GRAPH, ID, LANG, LIST, SET, VOCAB from ..shared.jsonld.util import _HAS_ORJSON, json, orjson +if TYPE_CHECKING: + from rdflib.graph import _ObjectType + + # In JSON-LD, a Literal cannot be Subject. So define a new type + from ..shared.jsonld.context import JSONLDSubjectType, Term + __all__ = ["JsonLDSerializer", "from_rdf"] @@ -188,7 +194,7 @@ def convert(self, graph: Graph): context = self.context - objs: List[Any] = [] + objs: list[Any] = [] for g in graphs: obj = {} graphname = None @@ -223,7 +229,7 @@ def convert(self, graph: Graph): return objs def from_graph(self, graph: Graph): - nodemap: Dict[Any, Any] = {} + nodemap: dict[Any, Any] = {} for s in set(graph.subjects()): ## only iri:s and unreferenced (rest will be promoted to top if needed) @@ -252,9 +258,11 @@ def process_subject(self, graph: Graph, s: IdentifiedNode, nodemap): nodemap[node_id] = node for p, o in graph.predicate_objects(s): - # type error: Argument 3 to "add_to_node" of "Converter" has incompatible type "Node"; expected "IdentifiedNode" - # type error: Argument 4 to "add_to_node" of "Converter" has incompatible type "Node"; expected "Identifier" - self.add_to_node(graph, s, p, o, node, nodemap) # type: ignore[arg-type] + # predicate_objects can return a lot of different types, + # but we only need to consider it to be a JSON-compatible type. + object_val = cast(Union[IdentifiedNode, Literal], o) + pred_val = cast(IdentifiedNode, p) + self.add_to_node(graph, s, pred_val, object_val, node, nodemap) return node @@ -263,49 +271,62 @@ def add_to_node( graph: Graph, s: IdentifiedNode, p: IdentifiedNode, - o: Identifier, - s_node: Dict[str, Any], + o: IdentifiedNode | Literal, + s_node: dict[str, Any], nodemap, ): context = self.context - + term: Optional[Term] = None if isinstance(o, Literal): - datatype = str(o.datatype) if o.datatype else None + _datatype = str(o.datatype) if o.datatype else None language = o.language - term = context.find_term(str(p), datatype, language=language) + term = context.find_term(str(p), _datatype, language=language) else: containers = [LIST, None] if graph.value(o, RDF.first) else [None] for container in containers: for coercion in (ID, VOCAB, UNDEF): - # type error: Argument 2 to "find_term" of "Context" has incompatible type "object"; expected "Union[str, Defined, None]" - # type error: Argument 3 to "find_term" of "Context" has incompatible type "Optional[str]"; expected "Union[Defined, str]" - term = context.find_term(str(p), coercion, container) # type: ignore[arg-type] + term = context.find_term(str(p), coercion, container) if term: break if term: break + language = None if term is None else term.language - node = None + node: Optional[str | list[Any] | dict[str, Any]] = None use_set = not context.active - if term: + if term is not None: p_key = term.name if term.type: node = self.type_coerce(o, term.type) - # type error: "Identifier" has no attribute "language" - elif term.language and o.language == term.language: # type: ignore[attr-defined] + elif ( + term.language and isinstance(o, Literal) and o.language == term.language + ): node = str(o) - # type error: Right operand of "and" is never evaluated - elif context.language and (term.language is None and o.language is None): # type: ignore[unreachable] - node = str(o) # type: ignore[unreachable] + elif context.language: + # TODO: MyPy thinks this is unreachable? + if isinstance(o, Literal) and ( # type: ignore[unreachable] + term.language is None and o.language is None + ): + node = str(o) if LIST in term.container: - node = [ - self.type_coerce(v, term.type) - or self.to_raw_value(graph, s, v, nodemap) - for v in self.to_collection(graph, o) - ] + assert isinstance( + o, IdentifiedNode + ), "Subject of a @list container must an a URI or BNode" + _col = self.to_collection(graph, o) + if _col is not None: + node = [] + for v in _col: + if isinstance(v, (IdentifiedNode, Literal)): + coerced = self.type_coerce(v, term.type) + else: + coerced = None + if coerced is not None: + node.append(coerced) + else: + node.append(self.to_raw_value(graph, s, v, nodemap)) elif LANG in term.container and language: value = s_node.setdefault(p_key, {}) values = value.get(language) @@ -345,7 +366,9 @@ def add_to_node( value = node s_node[p_key] = value - def type_coerce(self, o: Identifier, coerce_type: str): + def type_coerce( + self, o: IdentifiedNode | Literal, coerce_type: str + ) -> Optional[str | IdentifiedNode | Literal]: if coerce_type == ID: if isinstance(o, URIRef): return self.context.shrink_iri(o) @@ -361,15 +384,19 @@ def type_coerce(self, o: Identifier, coerce_type: str): return None def to_raw_value( - self, graph: Graph, s: IdentifiedNode, o: Identifier, nodemap: Dict[str, Any] + self, + graph: Graph, + s: JSONLDSubjectType, + o: _ObjectType, + nodemap: dict[str, Any], ): context = self.context - coll = self.to_collection(graph, o) + if isinstance(o, (URIRef, BNode)): + coll: Optional[list[Any]] = self.to_collection(graph, o) + else: + coll = None if coll is not None: - coll = [ - self.to_raw_value(graph, s, lo, nodemap) - for lo in self.to_collection(graph, o) - ] + coll = [self.to_raw_value(graph, s, lo, nodemap) for lo in coll] return {context.list_key: coll} elif isinstance(o, BNode): embed = ( @@ -407,27 +434,36 @@ def to_raw_value( else: return v - def to_collection(self, graph: Graph, l_: Identifier): + def to_collection( + self, graph: Graph, l_: JSONLDSubjectType + ) -> Optional[list[_ObjectType]]: if l_ != RDF.nil and not graph.value(l_, RDF.first): return None - list_nodes: List[Optional[_ObjectType]] = [] - chain = set([l_]) - while l_: - if l_ == RDF.nil: + list_nodes: list[_ObjectType] = [] + chain: set[_ObjectType] = set([l_]) + list_head: Optional[_ObjectType] = l_ + while list_head: + if list_head == RDF.nil: + # The only way to return a real result is to reach + # a rdf:nil node at the end of a rdf list. return list_nodes - if isinstance(l_, URIRef): + if isinstance(list_head, URIRef): return None first, rest = None, None - for p, o in graph.predicate_objects(l_): + for p, o in graph.predicate_objects(list_head): if not first and p == RDF.first: first = o elif not rest and p == RDF.rest: rest = o elif p != RDF.type or o != RDF.List: return None - list_nodes.append(first) - # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Identifier") - l_ = rest # type: ignore[assignment] - if l_ in chain: + if first is not None: + list_nodes.append(first) + if rest is None: + # TODO: If no rdf:rest is found, should we return the current list_nodes? return None - chain.add(l_) + list_head = rest + if list_head in chain: + return None # TODO: Should this just return the current list_nodes? + chain.add(list_head) + return None diff --git a/rdflib/plugins/serializers/n3.py b/rdflib/plugins/serializers/n3.py index d8036bba0..8c4cbab54 100644 --- a/rdflib/plugins/serializers/n3.py +++ b/rdflib/plugins/serializers/n3.py @@ -2,7 +2,9 @@ Notation 3 (N3) RDF graph serializer for RDFLib. """ -from rdflib.graph import Graph +from typing import cast + +from rdflib.graph import Graph, QuotedGraph from rdflib.namespace import OWL, Namespace from rdflib.plugins.serializers.turtle import OBJECT, SUBJECT, TurtleSerializer @@ -68,7 +70,7 @@ def s_clause(self, subject): if isinstance(subject, Graph): self.write("\n" + self.indent()) self.p_clause(subject, SUBJECT) - self.predicateList(subject) + self.predicateList(cast(QuotedGraph, subject)) self.write(" .") return True else: @@ -76,7 +78,7 @@ def s_clause(self, subject): def p_clause(self, node, position): if isinstance(node, Graph): - self.subjectDone(node) + self.subjectDone(cast(QuotedGraph, node)) if position is OBJECT: self.write(" ") self.write("{") diff --git a/rdflib/plugins/serializers/nt.py b/rdflib/plugins/serializers/nt.py index e87f949e3..f756b5068 100644 --- a/rdflib/plugins/serializers/nt.py +++ b/rdflib/plugins/serializers/nt.py @@ -2,7 +2,7 @@ import codecs import warnings -from typing import IO, TYPE_CHECKING, Optional, Tuple, Union +from typing import IO, TYPE_CHECKING, Optional from rdflib.graph import Graph from rdflib.serializer import Serializer @@ -94,7 +94,7 @@ def _quote_encode(l_: str) -> str: def _nt_unicode_error_resolver( err: UnicodeError, -) -> Tuple[Union[str, bytes], int]: +) -> tuple[str | bytes, int]: """ Do unicode char replaces as defined in https://www.w3.org/TR/2004/REC-rdf-testcases-20040210/#ntrip_strings """ diff --git a/rdflib/plugins/serializers/rdfxml.py b/rdflib/plugins/serializers/rdfxml.py index d6a2f6abb..7001bf1c6 100644 --- a/rdflib/plugins/serializers/rdfxml.py +++ b/rdflib/plugins/serializers/rdfxml.py @@ -1,7 +1,8 @@ from __future__ import annotations import xml.dom.minidom -from typing import IO, Dict, Generator, Optional, Set, Tuple +from collections.abc import Generator +from typing import IO, TYPE_CHECKING, Optional from xml.sax.saxutils import escape, quoteattr from rdflib.collection import Collection @@ -15,6 +16,9 @@ from .xmlwriter import ESCAPE_ENTITIES +if TYPE_CHECKING: + pass + __all__ = ["fix", "XMLSerializer", "PrettyXMLSerializer"] @@ -22,14 +26,13 @@ class XMLSerializer(Serializer): def __init__(self, store: Graph): super(XMLSerializer, self).__init__(store) - def __bindings(self) -> Generator[Tuple[str, URIRef], None, None]: + def __bindings(self) -> Generator[tuple[str, URIRef], None, None]: store = self.store nm = store.namespace_manager - bindings: Dict[str, URIRef] = {} + bindings: dict[str, URIRef] = {} for predicate in set(store.predicates()): - # type error: Argument 1 to "compute_qname_strict" of "NamespaceManager" has incompatible type "Node"; expected "str" - prefix, namespace, name = nm.compute_qname_strict(predicate) # type: ignore[arg-type] + prefix, namespace, name = nm.compute_qname_strict(predicate) bindings[prefix] = URIRef(namespace) RDFNS = URIRef("http://www.w3.org/1999/02/22-rdf-syntax-ns#") # noqa: N806 @@ -55,7 +58,7 @@ def serialize( elif self.store.base is not None: self.base = self.store.base self.__stream = stream - self.__serialized: Dict[Identifier, int] = {} + self.__serialized: dict[Identifier, int] = {} encoding = self.encoding self.write = write = lambda uni: stream.write(uni.encode(encoding, "replace")) @@ -85,8 +88,7 @@ def serialize( # write out triples by subject for subject in self.store.subjects(): - # type error: Argument 1 to "subject" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - self.subject(subject, 1) # type: ignore[arg-type] + self.subject(subject, 1) # endRDF write("\n") @@ -114,9 +116,7 @@ def subject(self, subject: Identifier, depth: int = 1) -> None: write(">\n") for predicate, object in self.store.predicate_objects(subject): - # type error: Argument 1 to "predicate" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - # type error: Argument 2 to "predicate" of "XMLSerializer" has incompatible type "Node"; expected "Identifier" - self.predicate(predicate, object, depth + 1) # type: ignore[arg-type] + self.predicate(predicate, object, depth + 1) write("%s\n" % (indent, element_name)) else: @@ -169,7 +169,7 @@ def fix(val: str) -> str: class PrettyXMLSerializer(Serializer): def __init__(self, store: Graph, max_depth=3): super(PrettyXMLSerializer, self).__init__(store) - self.forceRDFAbout: Set[URIRef] = set() + self.forceRDFAbout: set[URIRef] = set() def serialize( self, @@ -178,7 +178,7 @@ def serialize( encoding: Optional[str] = None, **args, ) -> None: - self.__serialized: Dict[Identifier, int] = {} + self.__serialized: dict[IdentifiedNode | Literal, int] = {} store = self.store # if base is given here, use that, if not and a base is set for the graph use that if base is not None: @@ -192,7 +192,7 @@ def serialize( self.writer = writer = XMLWriter(stream, nm, encoding) namespaces = {} - possible: Set[Node] = set(store.predicates()).union( + possible: set[Node] = set(store.predicates()).union( store.objects(None, RDF.type) ) @@ -212,7 +212,7 @@ def serialize( writer.namespaces(namespaces.items()) - subject: IdentifiedNode + subject: IdentifiedNode | Literal # Write out subjects that can not be inline # type error: Incompatible types in assignment (expression has type "Node", variable has type "IdentifiedNode") for subject in store.subjects(): # type: ignore[assignment] @@ -244,7 +244,7 @@ def serialize( # Set to None so that the memory can get garbage collected. self.__serialized = None # type: ignore[assignment] - def subject(self, subject: Identifier, depth: int = 1): + def subject(self, subject: IdentifiedNode | Literal, depth: int = 1): store = self.store writer = self.writer @@ -265,8 +265,7 @@ def subject(self, subject: Identifier, depth: int = 1): type = None element = type or RDFVOC.Description - # type error: Argument 1 to "push" of "XMLWriter" has incompatible type "Node"; expected "str" - writer.push(element) # type: ignore[arg-type] + writer.push(element) if isinstance(subject, BNode): @@ -284,14 +283,13 @@ def subj_as_obj_more_than(ceil): writer.attribute(RDFVOC.about, self.relativize(subject)) if (subject, None, None) in store: - for predicate, object in store.predicate_objects(subject): - if not (predicate == RDF.type and object == type): - # type error: Argument 1 to "predicate" of "PrettyXMLSerializer" has incompatible type "Node"; expected "Identifier" - # type error: Argument 2 to "predicate" of "PrettyXMLSerializer" has incompatible type "Node"; expected "Identifier" - self.predicate(predicate, object, depth + 1) # type: ignore[arg-type] + for _predicate, _object in store.predicate_objects(subject): + object_: IdentifiedNode | Literal = _object # type: ignore[assignment] + predicate: IdentifiedNode = _predicate # type: ignore[assignment] + if not (predicate == RDF.type and object_ == type): + self.predicate(predicate, object_, depth + 1) - # type error: Argument 1 to "pop" of "XMLWriter" has incompatible type "Node"; expected "Optional[str]" - writer.pop(element) # type: ignore[arg-type] + writer.pop(element) elif subject in self.forceRDFAbout: # TODO FIXME?: this looks like a duplicate of first condition @@ -301,7 +299,10 @@ def subj_as_obj_more_than(ceil): self.forceRDFAbout.remove(subject) # type: ignore[arg-type] def predicate( - self, predicate: Identifier, object: Identifier, depth: int = 1 + self, + predicate: IdentifiedNode, + object: IdentifiedNode | Literal, + depth: int = 1, ) -> None: writer = self.writer store = self.store @@ -364,7 +365,7 @@ def predicate( else: if first( store.triples_choices( - # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "Tuple[Identifier, URIRef, List[URIRef]]"; expected "Union[Tuple[List[Node], Node, Node], Tuple[Node, List[Node], Node], Tuple[Node, Node, List[Node]]]" + # type error: Argument 1 to "triples_choices" of "Graph" has incompatible type "tuple[Identifier, URIRef, list[URIRef]]"; expected "Union[tuple[List[Node], Node, Node], tuple[Node, list[Node], Node], tuple[Node, Node, list[Node]]]" (object, RDF.type, [OWL_NS.Class, RDFS.Class]) # type: ignore[arg-type] ) ) and isinstance(object, URIRef): diff --git a/rdflib/plugins/serializers/trig.py b/rdflib/plugins/serializers/trig.py index 984f80c5a..c072fc8fa 100644 --- a/rdflib/plugins/serializers/trig.py +++ b/rdflib/plugins/serializers/trig.py @@ -5,7 +5,7 @@ from __future__ import annotations -from typing import IO, TYPE_CHECKING, Dict, List, Optional, Tuple, Union +from typing import IO, TYPE_CHECKING, Optional, Union from rdflib.graph import ConjunctiveGraph, Graph from rdflib.plugins.serializers.turtle import TurtleSerializer @@ -56,9 +56,9 @@ def preprocess(self) -> None: def reset(self) -> None: super(TrigSerializer, self).reset() - self._contexts: Dict[ + self._contexts: dict[ _ContextType, - Tuple[List[_SubjectType], Dict[_SubjectType, bool]], + tuple[list[_SubjectType], dict[_SubjectType, bool]], ] = {} def serialize( diff --git a/rdflib/plugins/serializers/turtle.py b/rdflib/plugins/serializers/turtle.py index a26df04a6..d31ba9a22 100644 --- a/rdflib/plugins/serializers/turtle.py +++ b/rdflib/plugins/serializers/turtle.py @@ -6,17 +6,12 @@ from __future__ import annotations from collections import defaultdict +from collections.abc import Mapping, Sequence from typing import ( IO, TYPE_CHECKING, Any, - DefaultDict, - Dict, - List, - Mapping, Optional, - Sequence, - Tuple, ) from rdflib.exceptions import Error @@ -26,7 +21,7 @@ from rdflib.term import BNode, Literal, Node, URIRef if TYPE_CHECKING: - from rdflib.graph import _PredicateType, _SubjectType, _TripleType + from rdflib.graph import _ObjectType, _PredicateType, _SubjectType, _TripleType __all__ = ["RecursiveSerializer", "TurtleSerializer"] @@ -36,7 +31,7 @@ class RecursiveSerializer(Serializer): predicateOrder = [RDF.type, RDFS.label] maxDepth = 10 indentString = " " - roundtrip_prefixes: Tuple[Any, ...] = () + roundtrip_prefixes: tuple[Any, ...] = () def __init__(self, store: Graph): super(RecursiveSerializer, self).__init__(store) @@ -66,13 +61,13 @@ def isDone(self, subject: _SubjectType) -> bool: """Return true if subject is serialized""" return subject in self._serialized - def orderSubjects(self) -> List[_SubjectType]: - seen: Dict[_SubjectType, bool] = {} - subjects: List[_SubjectType] = [] + def orderSubjects(self) -> list[_SubjectType]: + seen: dict[_SubjectType, bool] = {} + subjects: list[_SubjectType] = [] for classURI in self.topClasses: members = list(self.store.subjects(RDF.type, classURI)) - members.sort() + members = sorted(members) subjects.extend(members) for member in members: @@ -102,12 +97,12 @@ def preprocessTriple(self, spo: _TripleType) -> None: def reset(self) -> None: self.depth = 0 # Typed none because nothing is using it ... - self.lists: Dict[None, None] = {} - self.namespaces: Dict[str, URIRef] = {} - self._references: DefaultDict[Node, int] = defaultdict(int) - self._serialized: Dict[_SubjectType, bool] = {} - self._subjects: Dict[_SubjectType, bool] = {} - self._topLevels: Dict[_SubjectType, bool] = {} + self.lists: dict[None, None] = {} + self.namespaces: dict[str, URIRef] = {} + self._references: defaultdict[Node, int] = defaultdict(int) + self._serialized: dict[_SubjectType, bool] = {} + self._subjects: dict[_SubjectType, bool] = {} + self._topLevels: dict[_SubjectType, bool] = {} if self.roundtrip_prefixes: if hasattr(self.roundtrip_prefixes, "__iter__"): @@ -120,12 +115,12 @@ def reset(self) -> None: def buildPredicateHash( self, subject: _SubjectType - ) -> Mapping[_PredicateType, List[Node]]: + ) -> Mapping[_PredicateType, list[_ObjectType]]: """ Build a hash key by predicate to a list of objects for the given subject """ - properties: Dict[_PredicateType, List[Node]] = {} + properties: dict[_PredicateType, list[_ObjectType]] = {} for s, p, o in self.store.triples((subject, None, None)): oList = properties.get(p, []) oList.append(o) @@ -133,27 +128,27 @@ def buildPredicateHash( return properties def sortProperties( - self, properties: Mapping[_PredicateType, List[Node]] - ) -> List[_PredicateType]: + self, properties: Mapping[_PredicateType, list[_ObjectType]] + ) -> list[_PredicateType]: """Take a hash from predicate uris to lists of values. Sort the lists of values. Return a sorted list of properties.""" # Sort object lists - for prop, objects in properties.items(): - objects.sort() + property_keys = list(properties.keys()) + for prop in property_keys: + properties[prop].sort() # Make sorted list of properties - propList: List[_PredicateType] = [] - seen: Dict[_PredicateType, bool] = {} - for prop in self.predicateOrder: - if (prop in properties) and (prop not in seen): - propList.append(prop) - seen[prop] = True - props = list(properties.keys()) - props.sort() - for prop in props: - if prop not in seen: - propList.append(prop) - seen[prop] = True + propList: list[_PredicateType] = [] + seen: dict[_PredicateType, bool] = {} + for prop1 in self.predicateOrder: + if (prop1 in property_keys) and (prop1 not in seen): + propList.append(prop1) + seen[prop1] = True + props = sorted(property_keys) + for prop2 in props: + if prop2 not in seen: + propList.append(prop2) + seen[prop2] = True return propList def subjectDone(self, subject: _SubjectType) -> None: @@ -183,9 +178,9 @@ class TurtleSerializer(RecursiveSerializer): indentString = " " def __init__(self, store: Graph): - self._ns_rewrite: Dict[str, str] = {} + self._ns_rewrite: dict[str, str] = {} super(TurtleSerializer, self).__init__(store) - self.keywords: Dict[Node, str] = {RDF.type: "a"} + self.keywords: dict[Node, str] = {RDF.type: "a"} self.reset() self.stream = None self._spacious = _SPACIOUS_OUTPUT @@ -217,8 +212,8 @@ def addNamespace(self, prefix: str, namespace: URIRef) -> str: # type: ignore[o def reset(self) -> None: super(TurtleSerializer, self).reset() - # typing as Dict[None, None] because nothing seems to be using it - self._shortNames: Dict[None, None] = {} + # typing as dict[None, None] because nothing seems to be using it + self._shortNames: dict[None, None] = {} self._started = False self._ns_rewrite = {} @@ -400,7 +395,7 @@ def p_squared(self, node: Node, position: int, newline: bool = False) -> bool: return True - def isValidList(self, l_: Node) -> bool: + def isValidList(self, l_: _SubjectType) -> bool: """ Checks if l is a valid RDF list, i.e. no nodes have other properties. """ @@ -416,7 +411,7 @@ def isValidList(self, l_: Node) -> bool: l_ = self.store.value(l_, RDF.rest) # type: ignore[assignment] return True - def doList(self, l_: Node) -> None: + def doList(self, l_: _SubjectType) -> None: while l_: item = self.store.value(l_, RDF.first) if item is not None: @@ -425,7 +420,7 @@ def doList(self, l_: Node) -> None: # type error: Incompatible types in assignment (expression has type "Optional[Node]", variable has type "Node") l_ = self.store.value(l_, RDF.rest) # type: ignore[assignment] - def predicateList(self, subject: Node, newline: bool = False) -> None: + def predicateList(self, subject: _SubjectType, newline: bool = False) -> None: properties = self.buildPredicateHash(subject) propList = self.sortProperties(properties) if len(propList) == 0: diff --git a/rdflib/plugins/serializers/xmlwriter.py b/rdflib/plugins/serializers/xmlwriter.py index 8c00521ad..c062d4f0d 100644 --- a/rdflib/plugins/serializers/xmlwriter.py +++ b/rdflib/plugins/serializers/xmlwriter.py @@ -1,7 +1,8 @@ from __future__ import annotations import codecs -from typing import IO, TYPE_CHECKING, Dict, Iterable, List, Optional, Tuple +from collections.abc import Iterable +from typing import IO, TYPE_CHECKING, Optional from xml.sax.saxutils import escape, quoteattr from rdflib.term import URIRef @@ -22,7 +23,7 @@ def __init__( namespace_manager: NamespaceManager, encoding: Optional[str] = None, decl: int = 1, - extra_ns: Optional[Dict[str, Namespace]] = None, + extra_ns: Optional[dict[str, Namespace]] = None, ): encoding = encoding or "utf-8" encoder, decoder, stream_reader, stream_writer = codecs.lookup(encoding) @@ -32,7 +33,7 @@ def __init__( if decl: # type error: No overload variant of "write" of "IO" matches argument type "str" stream.write('' % encoding) # type: ignore[call-overload] - self.element_stack: List[str] = [] + self.element_stack: list[str] = [] self.nm = namespace_manager self.extra_ns = extra_ns or {} self.closed = True @@ -73,7 +74,7 @@ def pop(self, uri: Optional[str] = None) -> None: self.parent = True def element( - self, uri: str, content: str, attributes: Dict[URIRef, str] = {} + self, uri: str, content: str, attributes: dict[URIRef, str] = {} ) -> None: """Utility method for adding a complete simple element""" self.push(uri) @@ -82,7 +83,7 @@ def element( self.text(content) self.pop() - def namespaces(self, namespaces: Iterable[Tuple[str, str]] = None) -> None: + def namespaces(self, namespaces: Iterable[tuple[str, str]] = None) -> None: if not namespaces: namespaces = self.nm.namespaces() diff --git a/rdflib/plugins/shared/jsonld/context.py b/rdflib/plugins/shared/jsonld/context.py index e6b668878..9c43b87e1 100644 --- a/rdflib/plugins/shared/jsonld/context.py +++ b/rdflib/plugins/shared/jsonld/context.py @@ -9,16 +9,11 @@ from __future__ import annotations from collections import namedtuple +from collections.abc import Collection, Generator from typing import ( TYPE_CHECKING, Any, - Collection, - Dict, - Generator, - List, Optional, - Set, - Tuple, Union, ) from urllib.parse import urljoin, urlsplit @@ -56,6 +51,13 @@ ) from .util import norm_url, source_to_json, split_iri +if TYPE_CHECKING: + from typing_extensions import TypeAlias + + from rdflib.term import IdentifiedNode + + JSONLDSubjectType: TypeAlias = IdentifiedNode + NODE_KEYS = {GRAPH, ID, INCLUDED, JSON, LIST, NEST, NONE, REV, SET, TYPE, VALUE, LANG} @@ -69,7 +71,7 @@ class Defined(int): URI_GEN_DELIMS = (":", "/", "?", "#", "[", "]", "@") _ContextSourceType = Union[ - List[Union[Dict[str, Any], str, None]], Dict[str, Any], str, None + list[Union[dict[str, Any], str, None]], dict[str, Any], str, None ] @@ -86,15 +88,15 @@ def __init__( self._base: Optional[str] self.base = base self.doc_base = base - self.terms: Dict[str, Any] = {} + self.terms: dict[str, Any] = {} # _alias maps NODE_KEY to list of aliases - self._alias: Dict[str, List[str]] = {} - self._lookup: Dict[Tuple[str, Any, Union[Defined, str], bool], Term] = {} - self._prefixes: Dict[str, Any] = {} + self._alias: dict[str, list[str]] = {} + self._lookup: dict[tuple[str, Any, Union[Defined, str], bool], Term] = {} + self._prefixes: dict[str, Any] = {} self.active = False self.parent: Optional[Context] = None self.propagate = True - self._context_cache: Dict[str, Any] = {} + self._context_cache: dict[str, Any] = {} if source: self.load(source) @@ -175,31 +177,31 @@ def get_context_for_type(self, node: Any) -> Optional[Context]: return self.parent if self.propagate is False else self - def get_id(self, obj: Dict[str, Any]) -> Any: + def get_id(self, obj: dict[str, Any]) -> Any: return self._get(obj, ID) - def get_type(self, obj: Dict[str, Any]) -> Any: + def get_type(self, obj: dict[str, Any]) -> Any: return self._get(obj, TYPE) - def get_language(self, obj: Dict[str, Any]) -> Any: + def get_language(self, obj: dict[str, Any]) -> Any: return self._get(obj, LANG) - def get_value(self, obj: Dict[str, Any]) -> Any: + def get_value(self, obj: dict[str, Any]) -> Any: return self._get(obj, VALUE) - def get_graph(self, obj: Dict[str, Any]) -> Any: + def get_graph(self, obj: dict[str, Any]) -> Any: return self._get(obj, GRAPH) - def get_list(self, obj: Dict[str, Any]) -> Any: + def get_list(self, obj: dict[str, Any]) -> Any: return self._get(obj, LIST) - def get_set(self, obj: Dict[str, Any]) -> Any: + def get_set(self, obj: dict[str, Any]) -> Any: return self._get(obj, SET) - def get_rev(self, obj: Dict[str, Any]) -> Any: + def get_rev(self, obj: dict[str, Any]) -> Any: return self._get(obj, REV) - def _get(self, obj: Dict[str, Any], key: str) -> Any: + def _get(self, obj: dict[str, Any], key: str) -> Any: for alias in self._alias.get(key, []): if alias in obj: return obj.get(alias) @@ -285,11 +287,11 @@ def add_term( def find_term( self, idref: str, - coercion: Optional[Union[str, Defined]] = None, - container: Union[Defined, str] = UNDEF, + coercion: Optional[str | Defined] = None, + container: Optional[Defined | str] = UNDEF, language: Optional[str] = None, reverse: bool = False, - ): + ) -> Optional[Term]: lu = self._lookup if coercion is None: @@ -375,7 +377,7 @@ def shrink_iri(self, iri: str) -> str: elif self._base: if str(iri) == self._base: return "" - # type error: Argument 1 to "startswith" of "str" has incompatible type "Optional[str]"; expected "Union[str, Tuple[str, ...]]" + # type error: Argument 1 to "startswith" of "str" has incompatible type "Optional[str]"; expected "Union[str, tuple[str, ...]]" elif iri.startswith(self._basedomain): # type: ignore[arg-type] # type error: Argument 1 to "len" has incompatible type "Optional[str]"; expected "Sized" return iri[len(self._basedomain) :] # type: ignore[arg-type] @@ -383,8 +385,8 @@ def shrink_iri(self, iri: str) -> str: def to_symbol(self, iri: str) -> Optional[str]: iri = str(iri) - term = self.find_term(iri) - if term: + term: Optional[Term] = self.find_term(iri) + if term is not None: return term.name ns, name = split_iri(iri) if ns == self.vocab: @@ -399,12 +401,12 @@ def load( self, source: _ContextSourceType, base: Optional[str] = None, - referenced_contexts: Set[Any] = None, + referenced_contexts: set[Any] = None, ): self.active = True - sources: List[Tuple[Optional[str], Union[Dict[str, Any], str, None]]] = [] - # "Union[List[Union[Dict[str, Any], str]], List[Dict[str, Any]], List[str]]" : expression - # "Union[List[Dict[str, Any]], Dict[str, Any], List[str], str]" : variable + sources: list[tuple[Optional[str], Union[dict[str, Any], str, None]]] = [] + # "Union[List[Union[Dict[str, Any], str]], list[Dict[str, Any]], list[str]]" : expression + # "Union[List[Dict[str, Any]], dict[str, Any], list[str], str]" : variable source = source if isinstance(source, list) else [source] referenced_contexts = referenced_contexts or set() self._prep_sources(base, source, sources, referenced_contexts) @@ -426,9 +428,9 @@ def _accept_term(self, key: str) -> bool: def _prep_sources( self, base: Optional[str], - inputs: Union[List[Union[Dict[str, Any], str, None]], List[str]], - sources: List[Tuple[Optional[str], Union[Dict[str, Any], str, None]]], - referenced_contexts: Set[str], + inputs: Union[list[Union[dict[str, Any], str, None]], list[str]], + sources: list[tuple[Optional[str], Union[dict[str, Any], str, None]]], + referenced_contexts: set[str], in_source_url: Optional[str] = None, ): for source in inputs: @@ -466,7 +468,7 @@ def _prep_sources( sources.append((source_url, source)) def _fetch_context( - self, source: str, base: Optional[str], referenced_contexts: Set[str] + self, source: str, base: Optional[str], referenced_contexts: set[str] ): # type error: Value of type variable "AnyStr" of "urljoin" cannot be "Optional[str]" source_url = urljoin(base, source) # type: ignore[type-var] @@ -492,9 +494,9 @@ def _fetch_context( def _read_source( self, - source: Dict[str, Any], + source: dict[str, Any], source_url: Optional[str] = None, - referenced_contexts: Optional[Set[str]] = None, + referenced_contexts: Optional[set[str]] = None, ): imports = source.get(IMPORT) if imports: @@ -530,9 +532,9 @@ def _read_source( def _read_term( self, - source: Dict[str, Any], + source: dict[str, Any], name: str, - dfn: Union[Dict[str, Any], str], + dfn: Union[dict[str, Any], str], protected: bool = False, ) -> None: idref = None @@ -587,7 +589,7 @@ def _read_term( v.remove(name) def _rec_expand( - self, source: Dict[str, Any], expr: Optional[str], prev: Optional[str] = None + self, source: dict[str, Any], expr: Optional[str], prev: Optional[str] = None ) -> Optional[str]: if expr == prev or expr in NODE_KEYS: return expr @@ -616,7 +618,7 @@ def _rec_expand( return self._rec_expand(source, nxt, expr) - def _prep_expand(self, expr: str) -> Tuple[bool, Optional[str], str]: + def _prep_expand(self, expr: str) -> tuple[bool, Optional[str], str]: if ":" not in expr: return True, None, expr pfx, local = expr.split(":", 1) @@ -625,7 +627,7 @@ def _prep_expand(self, expr: str) -> Tuple[bool, Optional[str], str]: else: return False, None, expr - def _get_source_id(self, source: Dict[str, Any], key: str) -> Optional[str]: + def _get_source_id(self, source: dict[str, Any], key: str) -> Optional[str]: # .. from source dict or if already defined term = source.get(key) if term is None: @@ -636,8 +638,8 @@ def _get_source_id(self, source: Dict[str, Any], key: str) -> Optional[str]: term = term.get(ID) return term - def _term_dict(self, term: Term) -> Union[Dict[str, Any], str]: - tdict: Dict[str, Any] = {} + def _term_dict(self, term: Term) -> Union[dict[str, Any], str]: + tdict: dict[str, Any] = {} if term.type != UNDEF: tdict[TYPE] = self.shrink_iri(term.type) if term.container: @@ -652,7 +654,7 @@ def _term_dict(self, term: Term) -> Union[Dict[str, Any], str]: return tdict[ID] return tdict - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """ Returns a dictionary representation of the context that can be serialized to JSON. diff --git a/rdflib/plugins/shared/jsonld/util.py b/rdflib/plugins/shared/jsonld/util.py index 097a90b70..9ff111315 100644 --- a/rdflib/plugins/shared/jsonld/util.py +++ b/rdflib/plugins/shared/jsonld/util.py @@ -5,7 +5,7 @@ import pathlib from html.parser import HTMLParser from io import StringIO, TextIOBase, TextIOWrapper -from typing import IO, TYPE_CHECKING, Any, Dict, List, Optional, TextIO, Tuple, Union +from typing import IO, TYPE_CHECKING, Any, Optional, TextIO, Union if TYPE_CHECKING: import json @@ -46,7 +46,7 @@ def source_to_json( ], fragment_id: Optional[str] = None, extract_all_scripts: Optional[bool] = False, -) -> Tuple[Union[Dict, List[Dict]], Any]: +) -> tuple[Union[dict, list[dict]], Any]: """Extract JSON from a source document. The source document can be JSON or HTML with embedded JSON script elements (type attribute = "application/ld+json"). @@ -71,7 +71,7 @@ def source_to_json( # It's hidden in the BytesIOWrapper 'wrapped' attribute b_stream = source.getByteStream() original_string: Optional[str] = None - json_dict: Union[Dict, List[Dict]] + json_dict: Union[dict, list[dict]] if isinstance(b_stream, BytesIOWrapper): wrapped_inner = cast(Union[str, StringIO, TextIOBase], b_stream.wrapped) if isinstance(wrapped_inner, str): @@ -198,7 +198,7 @@ def source_to_json( VOCAB_DELIMS = ("#", "/", ":") -def split_iri(iri: str) -> Tuple[str, Optional[str]]: +def split_iri(iri: str) -> tuple[str, Optional[str]]: for delim in VOCAB_DELIMS: at = iri.rfind(delim) if at > -1: @@ -293,7 +293,7 @@ def __init__( ): super().__init__() self.fragment_id = fragment_id - self.json: List[Dict] = [] + self.json: list[dict] = [] self.contains_json = False self.fragment_id_does_not_match = False self.base = None @@ -348,7 +348,7 @@ def handle_data(self, data): self.script_count += 1 - def get_json(self) -> List[Dict]: + def get_json(self) -> list[dict]: return self.json def get_base(self): diff --git a/rdflib/plugins/sparql/aggregates.py b/rdflib/plugins/sparql/aggregates.py index 12972e795..531e20d22 100644 --- a/rdflib/plugins/sparql/aggregates.py +++ b/rdflib/plugins/sparql/aggregates.py @@ -4,20 +4,12 @@ from __future__ import annotations +from collections.abc import Callable, Iterable, Mapping, MutableMapping from decimal import Decimal from typing import ( Any, - Callable, - Dict, - Iterable, - List, - Mapping, - MutableMapping, Optional, - Set, - Tuple, TypeVar, - Union, overload, ) @@ -44,7 +36,7 @@ def __init__(self, aggregation: CompValue): self.distinct = False else: self.distinct = aggregation.distinct - self.seen: Set[Any] = set() + self.seen: set[Any] = set() def dont_care(self, row: FrozenBindings) -> bool: """skips distinct test""" @@ -97,21 +89,19 @@ def use_row(self, row: FrozenBindings) -> bool: @overload -def type_safe_numbers(*args: int) -> Tuple[int]: ... +def type_safe_numbers(*args: int) -> tuple[int]: ... @overload -def type_safe_numbers( - *args: Union[Decimal, float, int] -) -> Tuple[Union[float, int]]: ... +def type_safe_numbers(*args: Decimal | float | int) -> tuple[float | int, ...]: ... -def type_safe_numbers(*args: Union[Decimal, float, int]) -> Iterable[Union[float, int]]: +def type_safe_numbers(*args: Decimal | float | int) -> Iterable[float | int]: if any(isinstance(arg, float) for arg in args) and any( isinstance(arg, Decimal) for arg in args ): return map(float, args) - # type error: Incompatible return value type (got "Tuple[Union[Decimal, float, int], ...]", expected "Iterable[Union[float, int]]") + # type error: Incompatible return value type (got "Tuple[Decimal|float|int, ...]", expected "Iterable[float, int]") # NOTE on type error: if args contains a Decimal it will nopt get here. return args # type: ignore[return-value] @@ -246,7 +236,7 @@ def get_value(self) -> None: class GroupConcat(Accumulator): - value: List[Literal] + value: list[Literal] def __init__(self, aggregation: CompValue): super(GroupConcat, self).__init__(aggregation) @@ -291,9 +281,9 @@ class Aggregator: "Aggregate_GroupConcat": GroupConcat, } - def __init__(self, aggregations: List[CompValue]): - self.bindings: Dict[Variable, Identifier] = {} - self.accumulators: Dict[str, Accumulator] = {} + def __init__(self, aggregations: list[CompValue]): + self.bindings: dict[Variable, Identifier] = {} + self.accumulators: dict[str, Accumulator] = {} for a in aggregations: accumulator_class = self.accumulator_classes.get(a.name) if accumulator_class is None: diff --git a/rdflib/plugins/sparql/algebra.py b/rdflib/plugins/sparql/algebra.py index 5cb22d265..a0bee7656 100644 --- a/rdflib/plugins/sparql/algebra.py +++ b/rdflib/plugins/sparql/algebra.py @@ -7,22 +7,15 @@ from __future__ import annotations -import collections import functools import operator import typing +from collections import defaultdict +from collections.abc import Callable, Iterable, Mapping from functools import reduce from typing import ( Any, - Callable, - DefaultDict, - Dict, - Iterable, - List, - Mapping, Optional, - Set, - Tuple, overload, ) @@ -46,11 +39,11 @@ from rdflib.term import BNode, Identifier, Literal, URIRef, Variable -def OrderBy(p: CompValue, expr: List[CompValue]) -> CompValue: +def OrderBy(p: CompValue, expr: list[CompValue]) -> CompValue: return CompValue("OrderBy", p=p, expr=expr) -def ToMultiSet(p: typing.Union[List[Dict[Variable, str]], CompValue]) -> CompValue: +def ToMultiSet(p: typing.Union[list[dict[Variable, str]], CompValue]) -> CompValue: return CompValue("ToMultiSet", p=p) @@ -71,7 +64,7 @@ def Graph(term: Identifier, graph: CompValue) -> CompValue: def BGP( - triples: Optional[List[Tuple[Identifier, Identifier, Identifier]]] = None + triples: Optional[list[tuple[Identifier, Identifier, Identifier]]] = None ) -> CompValue: return CompValue("BGP", triples=triples or []) @@ -90,23 +83,23 @@ def Extend( return CompValue("Extend", p=p, expr=expr, var=var) -def Values(res: List[Dict[Variable, str]]) -> CompValue: +def Values(res: list[dict[Variable, str]]) -> CompValue: return CompValue("values", res=res) -def Project(p: CompValue, PV: List[Variable]) -> CompValue: +def Project(p: CompValue, PV: list[Variable]) -> CompValue: return CompValue("Project", p=p, PV=PV) -def Group(p: CompValue, expr: Optional[List[Variable]] = None) -> CompValue: +def Group(p: CompValue, expr: Optional[list[Variable]] = None) -> CompValue: return CompValue("Group", p=p, expr=expr) def _knownTerms( - triple: Tuple[Identifier, Identifier, Identifier], - varsknown: Set[typing.Union[BNode, Variable]], - varscount: Dict[Identifier, int], -) -> Tuple[int, int, bool]: + triple: tuple[Identifier, Identifier, Identifier], + varsknown: set[typing.Union[BNode, Variable]], + varscount: dict[Identifier, int], +) -> tuple[int, int, bool]: return ( len( [ @@ -121,24 +114,24 @@ def _knownTerms( def reorderTriples( - l_: Iterable[Tuple[Identifier, Identifier, Identifier]] -) -> List[Tuple[Identifier, Identifier, Identifier]]: + l_: Iterable[tuple[Identifier, Identifier, Identifier]] +) -> list[tuple[Identifier, Identifier, Identifier]]: """ Reorder triple patterns so that we execute the ones with most bindings first """ - def _addvar(term: str, varsknown: Set[typing.Union[Variable, BNode]]): + def _addvar(term: str, varsknown: set[typing.Union[Variable, BNode]]): if isinstance(term, (Variable, BNode)): varsknown.add(term) # NOTE on type errors: most of these are because the same variable is used # for different types. - # type error: List comprehension has incompatible type List[Tuple[None, Tuple[Identifier, Identifier, Identifier]]]; expected List[Tuple[Identifier, Identifier, Identifier]] + # type error: List comprehension has incompatible type list[tuple[None, tuple[Identifier, Identifier, Identifier]]]; expected list[tuple[Identifier, Identifier, Identifier]] l_ = [(None, x) for x in l_] # type: ignore[misc] - varsknown: Set[typing.Union[BNode, Variable]] = set() - varscount: Dict[Identifier, int] = collections.defaultdict(int) + varsknown: set[typing.Union[BNode, Variable]] = set() + varscount: dict[Identifier, int] = defaultdict(int) for t in l_: for c in t[1]: if isinstance(c, (Variable, BNode)): @@ -153,10 +146,10 @@ def _addvar(term: str, varsknown: Set[typing.Union[Variable, BNode]]): # we sort by decorate/undecorate, since we need the value of the sort keys while i < len(l_): - # type error: Generator has incompatible item type "Tuple[Any, Identifier]"; expected "Tuple[Identifier, Identifier, Identifier]" - # type error: Argument 1 to "_knownTerms" has incompatible type "Identifier"; expected "Tuple[Identifier, Identifier, Identifier]" + # type error: Generator has incompatible item type "tuple[Any, Identifier]"; expected "tuple[Identifier, Identifier, Identifier]" + # type error: Argument 1 to "_knownTerms" has incompatible type "Identifier"; expected "tuple[Identifier, Identifier, Identifier]" l_[i:] = sorted((_knownTerms(x[1], varsknown, varscount), x[1]) for x in l_[i:]) # type: ignore[misc,arg-type] - # type error: Incompatible types in assignment (expression has type "str", variable has type "Tuple[Identifier, Identifier, Identifier]") + # type error: Incompatible types in assignment (expression has type "str", variable has type "tuple[Identifier, Identifier, Identifier]") t = l_[i][0][0] # type: ignore[assignment] # top block has this many terms bound j = 0 while i + j < len(l_) and l_[i + j][0][0] == t: @@ -165,15 +158,15 @@ def _addvar(term: str, varsknown: Set[typing.Union[Variable, BNode]]): j += 1 i += 1 - # type error: List comprehension has incompatible type List[Identifier]; expected List[Tuple[Identifier, Identifier, Identifier]] + # type error: List comprehension has incompatible type list[Identifier]; expected list[tuple[Identifier, Identifier, Identifier]] return [x[1] for x in l_] # type: ignore[misc] def triples( l: typing.Union[ # noqa: E741 - List[List[Identifier]], List[Tuple[Identifier, Identifier, Identifier]] + list[list[Identifier]], list[tuple[Identifier, Identifier, Identifier]] ] -) -> List[Tuple[Identifier, Identifier, Identifier]]: +) -> list[tuple[Identifier, Identifier, Identifier]]: _l = reduce(lambda x, y: x + y, l) if (len(_l) % 3) != 0: raise Exception("these aint triples") @@ -276,7 +269,7 @@ def _c(n): return e -def collectAndRemoveFilters(parts: List[CompValue]) -> Optional[Expr]: +def collectAndRemoveFilters(parts: list[CompValue]) -> Optional[Expr]: """ FILTER expressions apply to the whole group graph pattern in which @@ -297,7 +290,7 @@ def collectAndRemoveFilters(parts: List[CompValue]) -> Optional[Expr]: i += 1 if filters: - # type error: Argument 1 to "and_" has incompatible type "*List[Union[Expr, Literal, Variable]]"; expected "Expr" + # type error: Argument 1 to "and_" has incompatible type "*list[Union[Expr, Literal, Variable]]"; expected "Expr" return and_(*filters) # type: ignore[arg-type] return None @@ -337,7 +330,7 @@ def translateGroupGraphPattern(graphPattern: CompValue) -> CompValue: # The first output from translate cannot be None for a subselect query # as it can only be None for certain DESCRIBE queries. # type error: Argument 1 to "ToMultiSet" has incompatible type "Optional[CompValue]"; - # expected "Union[List[Dict[Variable, str]], CompValue]" + # expected "Union[list[dict[Variable, str]], CompValue]" return ToMultiSet(translate(graphPattern)[0]) # type: ignore[arg-type] if not graphPattern.part: @@ -345,7 +338,7 @@ def translateGroupGraphPattern(graphPattern: CompValue) -> CompValue: filters = collectAndRemoveFilters(graphPattern.part) - g: List[CompValue] = [] + g: list[CompValue] = [] for p in graphPattern.part: if p.name == "TriplesBlock": # merge adjacent TripleBlocks @@ -419,21 +412,23 @@ def _traverse( if isinstance(e, (list, ParseResults)): return [_traverse(x, visitPre, visitPost) for x in e] - elif isinstance(e, tuple): + # MyPy on Python 3.9 thinks this part is unreachable, I don't know why. + elif isinstance(e, tuple): # type: ignore[unreachable, unused-ignore] return tuple([_traverse(x, visitPre, visitPost) for x in e]) elif isinstance(e, CompValue): for k, val in e.items(): e[k] = _traverse(val, visitPre, visitPost) - _e = visitPost(e) + # MyPy on Python 3.9 thinks this part is unreachable, I don't know why. + _e = visitPost(e) # type: ignore[unreachable, unused-ignore] if _e is not None: return _e return e -def _traverseAgg(e, visitor: Callable[[Any, Any], Any] = lambda n, v: None): +def _traverseAgg(e: Any, visitor: Callable[[Any, Any], Any] = lambda n, v: None): """ Traverse a parse-tree, visit each node @@ -444,7 +439,8 @@ def _traverseAgg(e, visitor: Callable[[Any, Any], Any] = lambda n, v: None): if isinstance(e, (list, ParseResults, tuple)): res = [_traverseAgg(x, visitor) for x in e] - elif isinstance(e, CompValue): + # MyPy on Python 3.9 thinks this part is unreachable, I don't know why. + elif isinstance(e, CompValue): # type: ignore[unreachable, unused-ignore] for k, val in e.items(): if val is not None: res.append(_traverseAgg(val, visitor)) @@ -501,7 +497,7 @@ def _aggs(e, A) -> Optional[Variable]: # type: ignore[return] # type error: Missing return statement -def _findVars(x, res: Set[Variable]) -> Optional[CompValue]: # type: ignore[return] +def _findVars(x, res: set[Variable]) -> Optional[CompValue]: # type: ignore[return] """ Find all variables in a tree """ @@ -518,7 +514,7 @@ def _findVars(x, res: Set[Variable]) -> Optional[CompValue]: # type: ignore[ret return x -def _addVars(x, children: List[Set[Variable]]) -> Set[Variable]: +def _addVars(x, children: list[set[Variable]]) -> set[Variable]: """ find which variables may be bound by this part of the query """ @@ -552,7 +548,7 @@ def _addVars(x, children: List[Set[Variable]]) -> Set[Variable]: # type error: Missing return statement -def _sample(e: typing.Union[CompValue, List[Expr], Expr, List[str], Variable], v: Optional[Variable] = None) -> Optional[CompValue]: # type: ignore[return] +def _sample(e: typing.Union[CompValue, list[Expr], Expr, list[str], Variable], v: Optional[Variable] = None) -> Optional[CompValue]: # type: ignore[return] """ For each unaggregated variable V in expr Replace V with Sample(V) @@ -570,9 +566,9 @@ def _simplifyFilters(e: Any) -> Any: def translateAggregates( q: CompValue, M: CompValue -) -> Tuple[CompValue, List[Tuple[Variable, Variable]]]: - E: List[Tuple[Variable, Variable]] = [] - A: List[CompValue] = [] +) -> tuple[CompValue, list[tuple[Variable, Variable]]]: + E: list[tuple[Variable, Variable]] = [] + A: list[CompValue] = [] # collect/replace aggs in : # select expr as ?var @@ -606,11 +602,11 @@ def translateAggregates( def translateValues( v: CompValue, -) -> typing.Union[List[Dict[Variable, str]], CompValue]: +) -> typing.Union[list[dict[Variable, str]], CompValue]: # if len(v.var)!=len(v.value): # raise Exception("Unmatched vars and values in ValueClause: "+str(v)) - res: List[Dict[Variable, str]] = [] + res: list[dict[Variable, str]] = [] if not v.var: return res if not v.value: @@ -625,7 +621,7 @@ def translateValues( return Values(res) -def translate(q: CompValue) -> Tuple[Optional[CompValue], List[Variable]]: +def translate(q: CompValue) -> tuple[Optional[CompValue], list[Variable]]: """ http://www.w3.org/TR/sparql11-query/#convertSolMod @@ -636,7 +632,7 @@ def translate(q: CompValue) -> Tuple[Optional[CompValue], List[Variable]]: q.where = traverse(q.where, visitPost=translatePath) # TODO: Var scope test - VS: Set[Variable] = set() + VS: set[Variable] = set() # All query types have a WHERE clause EXCEPT some DESCRIBE queries # where only explicit IRIs are provided. @@ -840,17 +836,17 @@ def translatePrologue( def translateQuads( quads: CompValue, -) -> Tuple[ - List[Tuple[Identifier, Identifier, Identifier]], - DefaultDict[str, List[Tuple[Identifier, Identifier, Identifier]]], +) -> tuple[ + list[tuple[Identifier, Identifier, Identifier]], + defaultdict[str, list[tuple[Identifier, Identifier, Identifier]]], ]: if quads.triples: alltriples = triples(quads.triples) else: alltriples = [] - allquads: DefaultDict[str, List[Tuple[Identifier, Identifier, Identifier]]] = ( - collections.defaultdict(list) + allquads: defaultdict[str, list[tuple[Identifier, Identifier, Identifier]]] = ( + defaultdict(list) ) if quads.quadsNotTriples: @@ -894,10 +890,10 @@ def translateUpdate( Returns a list of SPARQL Update Algebra expressions """ - res: List[CompValue] = [] + res: list[CompValue] = [] prologue = None if not q.request: - # type error: Incompatible return value type (got "List[CompValue]", expected "Update") + # type error: Incompatible return value type (got "list[CompValue]", expected "Update") return res # type: ignore[return-value] for p, u in zip(q.prologue, q.request): prologue = translatePrologue(p, base, initNs, prologue) @@ -974,9 +970,7 @@ class _AlgebraTranslator: def __init__(self, query_algebra: Query): self.query_algebra = query_algebra - self.aggr_vars: DefaultDict[Identifier, List[Identifier]] = ( - collections.defaultdict(list) - ) + self.aggr_vars: defaultdict[Identifier, list[Identifier]] = defaultdict(list) self._alg_translation: str = "" def _replace( diff --git a/rdflib/plugins/sparql/datatypes.py b/rdflib/plugins/sparql/datatypes.py index bc06525a0..9943eab6e 100644 --- a/rdflib/plugins/sparql/datatypes.py +++ b/rdflib/plugins/sparql/datatypes.py @@ -4,7 +4,7 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Dict, List, Optional, Set +from typing import TYPE_CHECKING, Optional from rdflib.namespace import XSD @@ -12,7 +12,7 @@ from rdflib.term import URIRef -XSD_DTs: Set[URIRef] = set( +XSD_DTs: set[URIRef] = set( ( XSD.integer, XSD.decimal, @@ -43,7 +43,7 @@ XSD_Duration_DTs = set((XSD.duration, XSD.dayTimeDuration, XSD.yearMonthDuration)) -_sub_types: Dict[URIRef, List[URIRef]] = { +_sub_types: dict[URIRef, list[URIRef]] = { XSD.integer: [ XSD.nonPositiveInteger, XSD.negativeInteger, @@ -60,13 +60,13 @@ ], } -_super_types: Dict[URIRef, URIRef] = {} +_super_types: dict[URIRef, URIRef] = {} for superdt in XSD_DTs: for subdt in _sub_types.get(superdt, []): _super_types[subdt] = superdt # we only care about float, double, integer, decimal -_typePromotionMap: Dict[URIRef, Dict[URIRef, URIRef]] = { +_typePromotionMap: dict[URIRef, dict[URIRef, URIRef]] = { XSD.float: {XSD.integer: XSD.float, XSD.decimal: XSD.float, XSD.double: XSD.double}, XSD.double: { XSD.integer: XSD.double, diff --git a/rdflib/plugins/sparql/evaluate.py b/rdflib/plugins/sparql/evaluate.py index 82fe8034f..0c95af758 100644 --- a/rdflib/plugins/sparql/evaluate.py +++ b/rdflib/plugins/sparql/evaluate.py @@ -16,20 +16,14 @@ from __future__ import annotations -import collections import itertools import re +from collections import defaultdict, deque +from collections.abc import Generator, Iterable, Mapping from typing import ( TYPE_CHECKING, Any, - Deque, - Dict, - Generator, - Iterable, - List, - Mapping, Optional, - Tuple, Union, ) from urllib.parse import urlencode @@ -72,11 +66,11 @@ orjson = None # type: ignore[assignment, unused-ignore] _HAS_ORJSON = False -_Triple = Tuple[Identifier, Identifier, Identifier] +_Triple = tuple[Identifier, Identifier, Identifier] def evalBGP( - ctx: QueryContext, bgp: List[_Triple] + ctx: QueryContext, bgp: list[_Triple] ) -> Generator[FrozenBindings, None, None]: """ A basic graph pattern @@ -93,7 +87,7 @@ def evalBGP( _o = ctx[o] # type error: Item "None" of "Optional[Graph]" has no attribute "triples" - # type Argument 1 to "triples" of "Graph" has incompatible type "Tuple[Union[str, Path, None], Union[str, Path, None], Union[str, Path, None]]"; expected "Tuple[Optional[Node], Optional[Node], Optional[Node]]" + # Argument 1 to "triples" of "Graph" has incompatible type "tuple[Union[str, Path, None], Union[str, Path, None], Union[str, Path, None]]"; expected "tuple[Optional[Union[IdentifiedNode, Literal, QuotedGraph, Variable]], Optional[IdentifiedNode], Optional[Union[IdentifiedNode, Literal, QuotedGraph, Variable]]]" [arg-type] for ss, sp, so in ctx.graph.triples((_s, _p, _o)): # type: ignore[union-attr, arg-type] if None in (_s, _p, _o): c = ctx.push() @@ -101,20 +95,17 @@ def evalBGP( c = ctx if _s is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[s] = ss # type: ignore[assignment] + c[s] = ss try: if _p is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[p] = sp # type: ignore[assignment] + c[p] = sp except AlreadyBound: continue try: if _o is None: - # type error: Incompatible types in assignment (expression has type "Union[Node, Any]", target has type "Identifier") - c[o] = so # type: ignore[assignment] + c[o] = so except AlreadyBound: continue @@ -166,7 +157,7 @@ def evalJoin(ctx: QueryContext, join: CompValue) -> Generator[FrozenDict, None, return _join(a, b) -def evalUnion(ctx: QueryContext, union: CompValue) -> List[Any]: +def evalUnion(ctx: QueryContext, union: CompValue) -> list[Any]: branch1_branch2 = [] for x in evalPart(ctx, union.p1): branch1_branch2.append(x) @@ -382,7 +373,7 @@ def evalServiceQuery(ctx: QueryContext, part: CompValue): res = json_dict["results"]["bindings"] if len(res) > 0: for r in res: - # type error: Argument 2 to "_yieldBindingsFromServiceCallResult" has incompatible type "str"; expected "Dict[str, Dict[str, str]]" + # type error: Argument 2 to "_yieldBindingsFromServiceCallResult" has incompatible type "str"; expected "Dict[str, dict[str, str]]" for bound in _yieldBindingsFromServiceCallResult(ctx, r, variables): # type: ignore[arg-type] yield bound else: @@ -424,9 +415,9 @@ def _buildQueryStringForServiceCall(ctx: QueryContext, service_query: str) -> st def _yieldBindingsFromServiceCallResult( - ctx: QueryContext, r: Dict[str, Dict[str, str]], variables: List[str] + ctx: QueryContext, r: dict[str, dict[str, str]], variables: list[str] ) -> Generator[FrozenBindings, None, None]: - res_dict: Dict[Variable, Identifier] = {} + res_dict: dict[Variable, Identifier] = {} for var in variables: if var in r and r[var]: var_binding = r[var] @@ -468,9 +459,7 @@ def evalAggregateJoin( # p is always a Group, we always get a dict back group_expr = agg.p.expr - res: Dict[Any, Any] = collections.defaultdict( - lambda: Aggregator(aggregations=agg.A) - ) + res: dict[Any, Any] = defaultdict(lambda: Aggregator(aggregations=agg.A)) if group_expr is None: # no grouping, just COUNT in SELECT clause @@ -540,7 +529,7 @@ def evalReduced( # mixed data structure: set for lookup, deque for append/pop/remove mru_set = set() - mru_queue: Deque[Any] = collections.deque() + mru_queue: deque[Any] = deque() for row in evalPart(ctx, part.p): if row in mru_set: @@ -576,8 +565,8 @@ def evalProject(ctx: QueryContext, project: CompValue): def evalSelectQuery( ctx: QueryContext, query: CompValue -) -> Mapping[str, Union[str, List[Variable], Iterable[FrozenDict]]]: - res: Dict[str, Union[str, List[Variable], Iterable[FrozenDict]]] = {} +) -> Mapping[str, Union[str, list[Variable], Iterable[FrozenDict]]]: + res: dict[str, Union[str, list[Variable], Iterable[FrozenDict]]] = {} res["type_"] = "SELECT" res["bindings"] = evalPart(ctx, query.p) res["vars_"] = query.PV @@ -585,7 +574,7 @@ def evalSelectQuery( def evalAskQuery(ctx: QueryContext, query: CompValue) -> Mapping[str, Union[str, bool]]: - res: Dict[str, Union[bool, str]] = {} + res: dict[str, Union[bool, str]] = {} res["type_"] = "ASK" res["askAnswer"] = False for x in evalPart(ctx, query.p): @@ -609,14 +598,14 @@ def evalConstructQuery( for c in evalPart(ctx, query.p): graph += _fillTemplate(template, c) - res: Dict[str, Union[str, Graph]] = {} + res: dict[str, Union[str, Graph]] = {} res["type_"] = "CONSTRUCT" res["graph"] = graph return res -def evalDescribeQuery(ctx: QueryContext, query) -> Dict[str, Union[str, Graph]]: +def evalDescribeQuery(ctx: QueryContext, query) -> dict[str, Union[str, Graph]]: # Create a result graph and bind namespaces from the graph being queried graph = Graph() # type error: Item "None" of "Optional[Graph]" has no attribute "namespaces" @@ -644,7 +633,7 @@ def evalDescribeQuery(ctx: QueryContext, query) -> Dict[str, Union[str, Graph]]: # type error: Item "None" of "Optional[Graph]" has no attribute "cbd" ctx.graph.cbd(resource, target_graph=graph) # type: ignore[union-attr] - res: Dict[str, Union[str, Graph]] = {} + res: dict[str, Union[str, Graph]] = {} res["type_"] = "DESCRIBE" res["graph"] = graph diff --git a/rdflib/plugins/sparql/evalutils.py b/rdflib/plugins/sparql/evalutils.py index 1f737e469..b042ab1d7 100644 --- a/rdflib/plugins/sparql/evalutils.py +++ b/rdflib/plugins/sparql/evalutils.py @@ -1,18 +1,7 @@ from __future__ import annotations -import collections -from typing import ( - Any, - DefaultDict, - Generator, - Iterable, - Mapping, - Set, - Tuple, - TypeVar, - Union, - overload, -) +from collections import defaultdict +from typing import TYPE_CHECKING, Any, TypeVar, Union, overload from rdflib.plugins.sparql.operators import EBV from rdflib.plugins.sparql.parserutils import CompValue, Expr @@ -25,13 +14,20 @@ ) from rdflib.term import BNode, Identifier, Literal, URIRef, Variable -_ContextType = Union[FrozenBindings, QueryContext] +if TYPE_CHECKING: + from collections.abc import Generator, Iterable, Mapping + + from typing_extensions import TypeAlias + + from rdflib.graph import _TripleType + +_ContextType: TypeAlias = Union[FrozenBindings, QueryContext] _FrozenDictT = TypeVar("_FrozenDictT", bound=FrozenDict) def _diff( a: Iterable[_FrozenDictT], b: Iterable[_FrozenDictT], expr -) -> Set[_FrozenDictT]: +) -> set[_FrozenDictT]: res = set() for x in a: @@ -70,7 +66,7 @@ def _join( yield x.merge(y) -def _ebv(expr: Union[Literal, Variable, Expr], ctx: FrozenDict) -> bool: +def _ebv(expr: Literal | Variable | Expr, ctx: FrozenDict) -> bool: """ Return true/false for the given expr Either the expr is itself true/false @@ -101,22 +97,22 @@ def _ebv(expr: Union[Literal, Variable, Expr], ctx: FrozenDict) -> bool: @overload def _eval( - expr: Union[Literal, URIRef], + expr: Literal | URIRef, ctx: FrozenBindings, raise_not_bound_error: bool = ..., -) -> Union[Literal, URIRef]: ... +) -> Literal | URIRef: ... @overload def _eval( - expr: Union[Variable, Expr], + expr: Variable | Expr, ctx: FrozenBindings, raise_not_bound_error: bool = ..., -) -> Union[Any, SPARQLError]: ... +) -> Any | SPARQLError: ... def _eval( - expr: Union[Literal, URIRef, Variable, Expr], + expr: Literal | URIRef | Variable | Expr, ctx: FrozenBindings, raise_not_bound_error: bool = True, ) -> Any: @@ -139,7 +135,7 @@ def _eval( def _filter( - a: Iterable[FrozenDict], expr: Union[Literal, Variable, Expr] + a: Iterable[FrozenDict], expr: Literal | Variable | Expr ) -> Generator[FrozenDict, None, None]: for c in a: if _ebv(expr, c): @@ -147,16 +143,16 @@ def _filter( def _fillTemplate( - template: Iterable[Tuple[Identifier, Identifier, Identifier]], + template: Iterable[tuple[Identifier, Identifier, Identifier]], solution: _ContextType, -) -> Generator[Tuple[Identifier, Identifier, Identifier], None, None]: +) -> Generator[_TripleType, None, None]: """ For construct/deleteWhere and friends Fill a triple template with instantiated variables """ - bnodeMap: DefaultDict[BNode, BNode] = collections.defaultdict(BNode) + bnodeMap: defaultdict[BNode, BNode] = defaultdict(BNode) for t in template: s, p, o = t @@ -176,7 +172,7 @@ def _fillTemplate( _ValueT = TypeVar("_ValueT", Variable, BNode, URIRef, Literal) -def _val(v: _ValueT) -> Tuple[int, _ValueT]: +def _val(v: _ValueT) -> tuple[int, _ValueT]: """utilitity for ordering things""" if isinstance(v, Variable): return (0, v) diff --git a/rdflib/plugins/sparql/operators.py b/rdflib/plugins/sparql/operators.py index e4d19f664..ca8b7a904 100644 --- a/rdflib/plugins/sparql/operators.py +++ b/rdflib/plugins/sparql/operators.py @@ -18,7 +18,7 @@ import warnings from decimal import ROUND_HALF_DOWN, ROUND_HALF_UP, Decimal, InvalidOperation from functools import reduce -from typing import Any, Callable, Dict, NoReturn, Optional, Tuple, Union, overload +from typing import Any, Callable, NoReturn, Optional, Union, overload from urllib.parse import quote from pyparsing import ParseResults @@ -592,7 +592,7 @@ def Builtin_EXISTS(e: Expr, ctx: FrozenBindings) -> Literal: _CustomFunction = Callable[[Expr, FrozenBindings], Node] -_CUSTOM_FUNCTIONS: Dict[URIRef, Tuple[_CustomFunction, bool]] = {} +_CUSTOM_FUNCTIONS: dict[URIRef, tuple[_CustomFunction, bool]] = {} def register_custom_function( @@ -993,7 +993,9 @@ def simplify(expr: Any) -> Any: if isinstance(expr, (list, ParseResults)): return list(map(simplify, expr)) - if not isinstance(expr, CompValue): + # I don't know why MyPy thinks this is unreachable + # Something to do with the Any type and the isinstance calls above. + if not isinstance(expr, CompValue): # type: ignore[unreachable, unused-ignore] return expr if expr.name.endswith("Expression"): if expr.other is None: diff --git a/rdflib/plugins/sparql/parser.py b/rdflib/plugins/sparql/parser.py index 3ee230f53..665800c4f 100644 --- a/rdflib/plugins/sparql/parser.py +++ b/rdflib/plugins/sparql/parser.py @@ -8,9 +8,9 @@ import re import sys -from typing import Any, BinaryIO, List +from typing import Any, BinaryIO from typing import Optional as OptionalType -from typing import TextIO, Tuple, Union +from typing import TextIO, Union from pyparsing import CaselessKeyword as Keyword # watch out :) from pyparsing import ( @@ -46,22 +46,22 @@ def neg(literal: rdflib.Literal) -> rdflib.Literal: return rdflib.Literal(-literal, datatype=literal.datatype) -def setLanguage(terms: Tuple[Any, OptionalType[str]]) -> rdflib.Literal: +def setLanguage(terms: tuple[Any, OptionalType[str]]) -> rdflib.Literal: return rdflib.Literal(terms[0], lang=terms[1]) -def setDataType(terms: Tuple[Any, OptionalType[str]]) -> rdflib.Literal: +def setDataType(terms: tuple[Any, OptionalType[str]]) -> rdflib.Literal: return rdflib.Literal(terms[0], datatype=terms[1]) -def expandTriples(terms: ParseResults) -> List[Any]: +def expandTriples(terms: ParseResults) -> list[Any]: """ Expand ; and , syntax for repeat predicates, subjects """ # import pdb; pdb.set_trace() last_subject, last_predicate = None, None # Used for ; and , try: - res: List[Any] = [] + res: list[Any] = [] if DEBUG: print("Terms", terms) l_ = len(terms) @@ -117,7 +117,7 @@ def expandTriples(terms: ParseResults) -> List[Any]: raise -def expandBNodeTriples(terms: ParseResults) -> List[Any]: +def expandBNodeTriples(terms: ParseResults) -> list[Any]: """ expand [ ?p ?o ] syntax for implicit bnodes """ @@ -134,14 +134,14 @@ def expandBNodeTriples(terms: ParseResults) -> List[Any]: raise -def expandCollection(terms: ParseResults) -> List[List[Any]]: +def expandCollection(terms: ParseResults) -> list[list[Any]]: """ expand ( 1 2 3 ) notation for collections """ if DEBUG: print("Collection: ", terms) - res: List[Any] = [] + res: list[Any] = [] other = [] for x in terms: if isinstance(x, list): # is this a [ .. ] ? diff --git a/rdflib/plugins/sparql/parserutils.py b/rdflib/plugins/sparql/parserutils.py index 7b85eb659..2927dfc7a 100644 --- a/rdflib/plugins/sparql/parserutils.py +++ b/rdflib/plugins/sparql/parserutils.py @@ -28,15 +28,12 @@ from __future__ import annotations from collections import OrderedDict +from collections.abc import Callable, Mapping from types import MethodType from typing import ( TYPE_CHECKING, Any, - Callable, - List, - Mapping, Optional, - Tuple, TypeVar, Union, ) @@ -107,7 +104,7 @@ class ParamValue: """ def __init__( - self, name: str, tokenList: Union[List[Any], ParseResults], isList: bool + self, name: str, tokenList: Union[list[Any], ParseResults], isList: bool ): self.isList = isList self.name = name @@ -133,7 +130,7 @@ def __init__(self, name: str, expr, isList: bool = False): self.setName(name) self.addParseAction(self.postParse2) - def postParse2(self, tokenList: Union[List[Any], ParseResults]) -> ParamValue: + def postParse2(self, tokenList: Union[list[Any], ParseResults]) -> ParamValue: return ParamValue(self.name, tokenList, self.isList) @@ -280,7 +277,7 @@ def setEvalFn(self, evalfn: Callable[[Any, Any], Any]) -> Comp: def prettify_parsetree(t: ParseResults, indent: str = "", depth: int = 0) -> str: - out: List[str] = [] + out: list[str] = [] for e in t.asList(): out.append(_prettify_sub_parsetree(e, indent, depth + 1)) for k, v in sorted(t.items()): @@ -290,11 +287,11 @@ def prettify_parsetree(t: ParseResults, indent: str = "", depth: int = 0) -> str def _prettify_sub_parsetree( - t: Union[Identifier, CompValue, set, list, dict, Tuple, bool, None], + t: Union[Identifier, CompValue, set, list, dict, tuple, bool, None], indent: str = "", depth: int = 0, ) -> str: - out: List[str] = [] + out: list[str] = [] if isinstance(t, CompValue): out.append("%s%s> %s:\n" % (indent, " " * depth, t.name)) for k, v in t.items(): diff --git a/rdflib/plugins/sparql/processor.py b/rdflib/plugins/sparql/processor.py index de97d80bd..fe9e3fb1a 100644 --- a/rdflib/plugins/sparql/processor.py +++ b/rdflib/plugins/sparql/processor.py @@ -7,7 +7,8 @@ from __future__ import annotations -from typing import Any, Mapping, Optional, Union +from collections.abc import Mapping +from typing import Any, Optional, Union from rdflib.graph import Graph from rdflib.plugins.sparql.algebra import translateQuery, translateUpdate diff --git a/rdflib/plugins/sparql/results/csvresults.py b/rdflib/plugins/sparql/results/csvresults.py index 32b3e4212..bb80ac794 100644 --- a/rdflib/plugins/sparql/results/csvresults.py +++ b/rdflib/plugins/sparql/results/csvresults.py @@ -12,7 +12,7 @@ import codecs import csv from io import BufferedIOBase, TextIOBase -from typing import IO, Dict, List, Optional, Union, cast +from typing import IO, Optional, Union, cast from rdflib.plugins.sparql.processor import SPARQLResult from rdflib.query import Result, ResultParser, ResultSerializer @@ -43,8 +43,8 @@ def parse(self, source: IO, content_type: Optional[str] = None) -> Result: # ty return r def parseRow( - self, row: List[str], v: List[Variable] - ) -> Dict[Variable, Union[BNode, URIRef, Literal]]: + self, row: list[str], v: list[Variable] + ) -> dict[Variable, Union[BNode, URIRef, Literal]]: return dict( (var, val) for var, val in zip(v, [self.convertTerm(t) for t in row]) diff --git a/rdflib/plugins/sparql/results/jsonresults.py b/rdflib/plugins/sparql/results/jsonresults.py index cfc2dc1e1..fa2e940d6 100644 --- a/rdflib/plugins/sparql/results/jsonresults.py +++ b/rdflib/plugins/sparql/results/jsonresults.py @@ -12,10 +12,11 @@ from __future__ import annotations import json -from typing import IO, Any, Dict, Mapping, MutableSequence, Optional +from collections.abc import Mapping, MutableSequence +from typing import IO, TYPE_CHECKING, Any, Optional from rdflib.query import Result, ResultException, ResultParser, ResultSerializer -from rdflib.term import BNode, Identifier, Literal, URIRef, Variable +from rdflib.term import BNode, Literal, URIRef, Variable try: import orjson @@ -25,6 +26,10 @@ orjson = None # type: ignore[assignment, unused-ignore] _HAS_ORJSON = False +if TYPE_CHECKING: + from rdflib.query import QueryResultValueType + from rdflib.term import IdentifiedNode + class JSONResultParser(ResultParser): # type error: Signature of "parse" incompatible with supertype "ResultParser" @@ -48,7 +53,7 @@ def __init__(self, result: Result): # type error: Signature of "serialize" incompatible with supertype "ResultSerializer" def serialize(self, stream: IO, encoding: str = None) -> None: # type: ignore[override] - res: Dict[str, Any] = {} + res: dict[str, Any] = {} if self.result.type == "ASK": res["head"] = {} res["boolean"] = self.result.askAnswer @@ -84,17 +89,20 @@ def serialize(self, stream: IO, encoding: str = None) -> None: # type: ignore[o else: stream.write(r_str) - def _bindingToJSON(self, b: Mapping[Variable, Identifier]) -> Dict[Variable, Any]: + def _bindingToJSON( + self, b: Mapping[Variable, QueryResultValueType] + ) -> dict[Variable, Any]: res = {} for var in b: j = termToJSON(self, b[var]) if j is not None: + # TODO: Why is this not simply `res[var] = j`? res[var] = termToJSON(self, b[var]) return res class JSONResult(Result): - def __init__(self, json: Dict[str, Any]): + def __init__(self, json: dict[str, Any]): self.json = json if "boolean" in json: type_ = "ASK" @@ -111,17 +119,17 @@ def __init__(self, json: Dict[str, Any]): self.bindings = self._get_bindings() self.vars = [Variable(x) for x in json["head"]["vars"]] - def _get_bindings(self) -> MutableSequence[Mapping[Variable, Identifier]]: - ret: MutableSequence[Mapping[Variable, Identifier]] = [] + def _get_bindings(self) -> MutableSequence[Mapping[Variable, QueryResultValueType]]: + ret: MutableSequence[Mapping[Variable, QueryResultValueType]] = [] for row in self.json["results"]["bindings"]: - outRow: Dict[Variable, Identifier] = {} + outRow: dict[Variable, QueryResultValueType] = {} for k, v in row.items(): outRow[Variable(k)] = parseJsonTerm(v) ret.append(outRow) return ret -def parseJsonTerm(d: Dict[str, str]) -> Identifier: +def parseJsonTerm(d: dict[str, str]) -> IdentifiedNode | Literal: """rdflib object (Literal, URIRef, BNode) for the given json-format dict. input is like: @@ -143,8 +151,8 @@ def parseJsonTerm(d: Dict[str, str]) -> Identifier: def termToJSON( - self: JSONResultSerializer, term: Optional[Identifier] -) -> Optional[Dict[str, str]]: + self: JSONResultSerializer, term: Optional[IdentifiedNode | Literal] +) -> Optional[dict[str, str]]: if isinstance(term, URIRef): return {"type": "uri", "value": str(term)} elif isinstance(term, Literal): diff --git a/rdflib/plugins/sparql/results/rdfresults.py b/rdflib/plugins/sparql/results/rdfresults.py index c59a40c14..fe3040e57 100644 --- a/rdflib/plugins/sparql/results/rdfresults.py +++ b/rdflib/plugins/sparql/results/rdfresults.py @@ -1,22 +1,28 @@ from __future__ import annotations -from typing import IO, Any, MutableMapping, Optional, Union +from typing import IO, TYPE_CHECKING, Any, Optional, cast from rdflib.graph import Graph from rdflib.namespace import RDF, Namespace from rdflib.query import Result, ResultParser -from rdflib.term import Node, Variable +from rdflib.term import Literal, Variable + +if TYPE_CHECKING: + from rdflib.graph import _ObjectType + from rdflib.term import IdentifiedNode RS = Namespace("http://www.w3.org/2001/sw/DataAccess/tests/result-set#") class RDFResultParser(ResultParser): - def parse(self, source: Union[IO, Graph], **kwargs: Any) -> Result: + """This ResultParser is only used for DAWG standardised SPARQL tests.""" + + def parse(self, source: IO | Graph, **kwargs: Any) -> Result: return RDFResult(source, **kwargs) class RDFResult(Result): - def __init__(self, source: Union[IO, Graph], **kwargs: Any): + def __init__(self, source: IO | Graph, **kwargs: Any): if not isinstance(source, Graph): graph = Graph() graph.parse(source, **kwargs) @@ -32,9 +38,9 @@ def __init__(self, source: Union[IO, Graph], **kwargs: Any): # use a new graph g = Graph() g += graph - + askAnswer: Optional[Literal] = None else: - askAnswer = graph.value(rs, RS.boolean) + askAnswer = cast(Optional[Literal], graph.value(rs, RS.boolean)) if askAnswer is not None: type_ = "ASK" @@ -44,27 +50,35 @@ def __init__(self, source: Union[IO, Graph], **kwargs: Any): Result.__init__(self, type_) if type_ == "SELECT": - # type error: Argument 1 to "Variable" has incompatible type "Node"; expected "str" - self.vars = [Variable(v) for v in graph.objects(rs, RS.resultVariable)] # type: ignore[arg-type] + self.vars = [ + # Technically we should check for QuotedGraph here, to make MyPy happy + Variable(v.identifier if isinstance(v, Graph) else v) # type: ignore[unreachable] + for v in graph.objects(rs, RS.resultVariable) + ] self.bindings = [] for s in graph.objects(rs, RS.solution): - sol: MutableMapping[Variable, Optional[Node]] = {} + sol: dict[Variable, IdentifiedNode | Literal] = {} for b in graph.objects(s, RS.binding): - # type error: Argument 1 to "Variable" has incompatible type "Optional[Node]"; expected "str" - sol[Variable(graph.value(b, RS.variable))] = graph.value( # type: ignore[arg-type] - b, RS.value - ) - # error: Argument 1 to "append" of "list" has incompatible type "MutableMapping[Variable, Optional[Node]]"; expected "Mapping[Variable, Identifier]" - self.bindings.append(sol) # type: ignore[arg-type] + var_name: Optional[_ObjectType | str] = graph.value(b, RS.variable) + if var_name is None: + continue + # Technically we should check for QuotedGraph here, to make MyPy happy + elif isinstance(var_name, Graph): # type: ignore[unreachable] + var_name = var_name.identifier # type: ignore[unreachable] + var_val = graph.value(b, RS.value) + if var_val is None: + continue + elif isinstance(var_val, (Graph, Variable)): + raise ValueError(f"Malformed rdf result binding {var_name}") + sol[Variable(var_name)] = var_val + self.bindings.append(sol) elif type_ == "ASK": - # type error: Item "Node" of "Optional[Node]" has no attribute "value" - # type error: Item "None" of "Optional[Node]" has no attribute "value" - self.askAnswer = askAnswer.value # type: ignore[union-attr] - # type error: Item "Node" of "Optional[Node]" has no attribute "value" - # type error: Item "None" of "Optional[Node]" has no attribute "value" - if askAnswer.value is None: # type: ignore[union-attr] + if askAnswer is None: + raise Exception("Malformed boolean in ask answer!") + self.askAnswer = askAnswer.value + if askAnswer.value is None: raise Exception("Malformed boolean in ask answer!") elif type_ == "CONSTRUCT": self.graph = g diff --git a/rdflib/plugins/sparql/results/tsvresults.py b/rdflib/plugins/sparql/results/tsvresults.py index 54b516d0d..b5f3461af 100644 --- a/rdflib/plugins/sparql/results/tsvresults.py +++ b/rdflib/plugins/sparql/results/tsvresults.py @@ -20,6 +20,7 @@ ZeroOrMore, ) +from rdflib import IdentifiedNode from rdflib.plugins.sparql.parser import ( BLANK_NODE_LABEL, IRIREF, @@ -32,7 +33,7 @@ ) from rdflib.plugins.sparql.parserutils import Comp, CompValue, Param from rdflib.query import Result, ResultParser -from rdflib.term import BNode, URIRef +from rdflib.term import BNode, URIRef, Variable from rdflib.term import Literal as RDFLiteral ParserElement.setDefaultWhitespaceChars(" \n") @@ -86,20 +87,28 @@ def parse(self, source: IO, content_type: typing.Optional[str] = None) -> Result continue row = ROW.parseString(line, parseAll=True) - # type error: Generator has incompatible item type "object"; expected "Identifier" - r.bindings.append(dict(zip(r.vars, (self.convertTerm(x) for x in row)))) # type: ignore[misc] - + this_row_dict: dict[Variable, IdentifiedNode | RDFLiteral] = {} + for var, val_read in zip(r.vars, row): + val = self.convertTerm(val_read) + if val is None: + # Skip unbound vars + continue + this_row_dict[var] = val + if len(this_row_dict) > 0: + r.bindings.append(this_row_dict) return r def convertTerm( self, t: Union[object, RDFLiteral, BNode, CompValue, URIRef] - ) -> typing.Optional[Union[object, BNode, URIRef, RDFLiteral]]: + ) -> typing.Optional[BNode | URIRef | RDFLiteral]: if t is NONE_VALUE: return None - if isinstance(t, CompValue): + elif isinstance(t, CompValue): if t.name == "literal": return RDFLiteral(t.string, lang=t.lang, datatype=t.datatype) else: raise Exception("I dont know how to handle this: %s" % (t,)) - else: + elif isinstance(t, (RDFLiteral, BNode, URIRef)): return t + else: + raise ValueError(f"Unexpected type {type(t)} found in TSV result") diff --git a/rdflib/plugins/sparql/results/txtresults.py b/rdflib/plugins/sparql/results/txtresults.py index 86d8933e3..8bdf2b53d 100644 --- a/rdflib/plugins/sparql/results/txtresults.py +++ b/rdflib/plugins/sparql/results/txtresults.py @@ -1,7 +1,7 @@ from __future__ import annotations from io import StringIO -from typing import IO, List, Optional, Union +from typing import IO, Optional, Union from rdflib.namespace import NamespaceManager from rdflib.query import ResultSerializer @@ -58,7 +58,7 @@ def c(s, w): if not self.result: string_stream.write("(no results)\n") else: - keys: List[Variable] = self.result.vars # type: ignore[assignment] + keys: list[Variable] = self.result.vars # type: ignore[assignment] maxlen = [0] * len(keys) b = [ # type error: Value of type "Union[Tuple[Node, Node, Node], bool, ResultRow]" is not indexable diff --git a/rdflib/plugins/sparql/results/xmlresults.py b/rdflib/plugins/sparql/results/xmlresults.py index 3cc6b2c38..a0debafe4 100644 --- a/rdflib/plugins/sparql/results/xmlresults.py +++ b/rdflib/plugins/sparql/results/xmlresults.py @@ -12,17 +12,15 @@ import logging import xml.etree.ElementTree as xml_etree # noqa: N813 +from collections.abc import Sequence from io import BytesIO from typing import ( IO, TYPE_CHECKING, Any, BinaryIO, - Dict, Optional, - Sequence, TextIO, - Tuple, Union, cast, ) @@ -209,8 +207,8 @@ def write_header(self, allvarsL: Sequence[Variable]) -> None: self.writer.startElementNS( (SPARQL_XML_NAMESPACE, "variable"), "variable", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" [arg-type] + # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[tuple[None, str], str]"; expected "Mapping[tuple[str, str], str]" + # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[tuple[None, str], str]"; expected "Mapping[tuple[str, str], str]" [arg-type] AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type] ) self.writer.endElementNS((SPARQL_XML_NAMESPACE, "variable"), "variable") @@ -243,17 +241,17 @@ def write_end_result(self) -> None: def write_binding(self, name: Variable, val: Identifier) -> None: assert self._resultStarted - attr_vals: Dict[Tuple[Optional[str], str], str] = { + attr_vals: dict[tuple[Optional[str], str], str] = { (None, "name"): str(name), } - attr_qnames: Dict[Tuple[Optional[str], str], str] = { + attr_qnames: dict[tuple[Optional[str], str], str] = { (None, "name"): "name", } self.writer.startElementNS( (SPARQL_XML_NAMESPACE, "binding"), "binding", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[None, str], str]"; expected "Mapping[Tuple[str, str], str]" + # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[tuple[None, str], str]"; expected "Mapping[tuple[str, str], str]" + # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[tuple[None, str], str]"; expected "Mapping[tuple[str, str], str]" AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type, unused-ignore] ) @@ -282,8 +280,8 @@ def write_binding(self, name: Variable, val: Identifier) -> None: self.writer.startElementNS( (SPARQL_XML_NAMESPACE, "literal"), "literal", - # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[Tuple[Optional[str], str], str]"; expected "Mapping[Tuple[str, str], str]" - # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[Tuple[Optional[str], str], str]"; expected "Mapping[Tuple[str, str], str]" + # type error: Argument 1 to "AttributesNSImpl" has incompatible type "Dict[tuple[Optional[str], str], str]"; expected "Mapping[tuple[str, str], str]" + # type error: Argument 2 to "AttributesNSImpl" has incompatible type "Dict[tuple[Optional[str], str], str]"; expected "Mapping[tuple[str, str], str]" AttributesNSImpl(attr_vals, attr_qnames), # type: ignore[arg-type, unused-ignore] ) self.writer.characters(val) diff --git a/rdflib/plugins/sparql/sparql.py b/rdflib/plugins/sparql/sparql.py index 8249a0ee8..dd6eff999 100644 --- a/rdflib/plugins/sparql/sparql.py +++ b/rdflib/plugins/sparql/sparql.py @@ -4,17 +4,11 @@ import datetime import itertools import typing as t -from collections.abc import Mapping, MutableMapping +from collections.abc import Container, Generator, Iterable, Mapping, MutableMapping from typing import ( TYPE_CHECKING, Any, - Container, - Dict, - Generator, - Iterable, - List, Optional, - Tuple, TypeVar, Union, ) @@ -65,7 +59,7 @@ class Bindings(MutableMapping): """ def __init__(self, outer: Optional[Bindings] = None, d=[]): - self._d: Dict[str, str] = dict(d) + self._d: dict[str, str] = dict(d) self.outer = outer def __getitem__(self, key: str) -> str: @@ -120,7 +114,7 @@ class FrozenDict(Mapping): """ def __init__(self, *args: Any, **kwargs: Any): - self._d: Dict[Identifier, Identifier] = dict(*args, **kwargs) + self._d: dict[Identifier, Identifier] = dict(*args, **kwargs) self._hash: Optional[int] = None def __iter__(self): @@ -251,7 +245,7 @@ class QueryContext: def __init__( self, graph: Optional[Graph] = None, - bindings: Optional[Union[Bindings, FrozenBindings, List[Any]]] = None, + bindings: Optional[Union[Bindings, FrozenBindings, list[Any]]] = None, initBindings: Optional[Mapping[str, Identifier]] = None, datasetClause=None, ): @@ -304,7 +298,7 @@ def now(self) -> datetime.datetime: return self._now def clone( - self, bindings: Optional[Union[FrozenBindings, Bindings, List[Any]]] = None + self, bindings: Optional[Union[FrozenBindings, Bindings, list[Any]]] = None ) -> QueryContext: r = QueryContext( self._dataset if self._dataset is not None else self.graph, @@ -485,7 +479,7 @@ class Query: def __init__(self, prologue: Prologue, algebra: CompValue): self.prologue = prologue self.algebra = algebra - self._original_args: Tuple[str, Mapping[str, str], Optional[str]] + self._original_args: tuple[str, Mapping[str, str], Optional[str]] class Update: @@ -493,7 +487,7 @@ class Update: A parsed and translated update """ - def __init__(self, prologue: Prologue, algebra: List[CompValue]): + def __init__(self, prologue: Prologue, algebra: list[CompValue]): self.prologue = prologue self.algebra = algebra - self._original_args: Tuple[str, Mapping[str, str], Optional[str]] + self._original_args: tuple[str, Mapping[str, str], Optional[str]] diff --git a/rdflib/plugins/sparql/update.py b/rdflib/plugins/sparql/update.py index cd22a7520..3acf03b52 100644 --- a/rdflib/plugins/sparql/update.py +++ b/rdflib/plugins/sparql/update.py @@ -6,7 +6,8 @@ from __future__ import annotations -from typing import TYPE_CHECKING, Iterator, Mapping, Optional, Sequence +from collections.abc import Iterator, Mapping, Sequence +from typing import TYPE_CHECKING, Optional from rdflib.graph import Graph from rdflib.plugins.sparql.evaluate import evalBGP, evalPart diff --git a/rdflib/plugins/stores/auditable.py b/rdflib/plugins/stores/auditable.py index 7a9748c69..7fe536b25 100644 --- a/rdflib/plugins/stores/auditable.py +++ b/rdflib/plugins/stores/auditable.py @@ -18,7 +18,8 @@ from __future__ import annotations import threading -from typing import TYPE_CHECKING, Any, Generator, Iterator, List, Optional, Tuple +from collections.abc import Generator, Iterator +from typing import TYPE_CHECKING, Any, Optional from rdflib.graph import ConjunctiveGraph, Graph from rdflib.store import Store @@ -51,8 +52,8 @@ def __init__(self, store: Store): # info to reverse the removal of a quoted statement self.formula_aware = False # store.formula_aware self.transaction_aware = True # This is only half true - self.reverseOps: List[ - Tuple[ + self.reverseOps: list[ + tuple[ Optional[_SubjectType], Optional[_PredicateType], Optional[_ObjectType], @@ -142,7 +143,7 @@ def remove( def triples( self, triple: _TriplePatternType, context: Optional[_ContextType] = None - ) -> Iterator[Tuple[_TripleType, Iterator[Optional[_ContextType]]]]: + ) -> Iterator[tuple[_TripleType, Iterator[Optional[_ContextType]]]]: (su, pr, ob) = triple context = ( context.__class__(self.store, context.identifier) @@ -175,7 +176,7 @@ def prefix(self, namespace: URIRef) -> Optional[str]: def namespace(self, prefix: str) -> Optional[URIRef]: return self.store.namespace(prefix) - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: + def namespaces(self) -> Iterator[tuple[str, URIRef]]: return self.store.namespaces() def commit(self) -> None: diff --git a/rdflib/plugins/stores/berkeleydb.py b/rdflib/plugins/stores/berkeleydb.py index 12009787c..13eaa7170 100644 --- a/rdflib/plugins/stores/berkeleydb.py +++ b/rdflib/plugins/stores/berkeleydb.py @@ -1,10 +1,11 @@ from __future__ import annotations import logging +from collections.abc import Callable, Generator from os import mkdir from os.path import abspath, exists from threading import Thread -from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Tuple +from typing import TYPE_CHECKING, Any, Optional from urllib.request import pathname2url from rdflib.store import NO_STORE, VALID_STORE, Store @@ -49,14 +50,14 @@ def bb(u: str) -> bytes: ] -_ToKeyFunc = Callable[[Tuple[bytes, bytes, bytes], bytes], bytes] -_FromKeyFunc = Callable[[bytes], Tuple[bytes, bytes, bytes, bytes]] +_ToKeyFunc = Callable[[tuple[bytes, bytes, bytes], bytes], bytes] +_FromKeyFunc = Callable[[bytes], tuple[bytes, bytes, bytes, bytes]] _GetPrefixFunc = Callable[ - [Tuple[str, str, str], Optional[str]], Generator[str, None, None] + [tuple[str, str, str], Optional[str]], Generator[str, None, None] ] _ResultsFromKeyFunc = Callable[ [bytes, Optional[Node], Optional[Node], Optional[Node], bytes], - Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]], + tuple[tuple[Node, Node, Node], Generator[Node, None, None]], ] @@ -100,7 +101,7 @@ def __init__( super(BerkeleyDB, self).__init__(configuration) self._loads = self.node_pickler.loads self._dumps = self.node_pickler.dumps - self.__indicies_info: List[Tuple[Any, _ToKeyFunc, _FromKeyFunc]] + self.__indicies_info: list[tuple[Any, _ToKeyFunc, _FromKeyFunc]] def __get_identifier(self) -> Optional[Identifier]: return self.__identifier @@ -157,12 +158,12 @@ def open(self, path: str, create: bool = True) -> Optional[int]: dbsetflags = 0 # create and open the DBs - self.__indicies: List[db.DB] = [ + self.__indicies: list[db.DB] = [ None, ] * 3 # NOTE on type ingore: this is because type checker does not like this # way of initializing, using a temporary variable will solve it. - # type error: error: List item 0 has incompatible type "None"; expected "Tuple[Any, Callable[[Tuple[bytes, bytes, bytes], bytes], bytes], Callable[[bytes], Tuple[bytes, bytes, bytes, bytes]]]" + # type error: error: List item 0 has incompatible type "None"; expected "tuple[Any, Callable[[tuple[bytes, bytes, bytes], bytes], bytes], Callable[[bytes], tuple[bytes, bytes, bytes, bytes]]]" self.__indicies_info = [ None, # type: ignore[list-item] ] * 3 @@ -177,11 +178,11 @@ def open(self, path: str, create: bool = True) -> Optional[int]: self.__indicies[i] = index self.__indicies_info[i] = (index, to_key_func(i), from_key_func(i)) - lookup: Dict[ - int, Tuple[db.DB, _GetPrefixFunc, _FromKeyFunc, _ResultsFromKeyFunc] + lookup: dict[ + int, tuple[db.DB, _GetPrefixFunc, _FromKeyFunc, _ResultsFromKeyFunc] ] = {} for i in range(0, 8): - results: List[Tuple[Tuple[int, int], int, int]] = [] + results: list[tuple[tuple[int, int], int, int]] = [] for start in range(0, 3): score = 1 len = 0 @@ -197,12 +198,12 @@ def open(self, path: str, create: bool = True) -> Optional[int]: results.sort() # NOTE on type error: this is because the variable `score` is # reused with different type - # type error: Incompatible types in assignment (expression has type "Tuple[int, int]", variable has type "int") + # type error: Incompatible types in assignment (expression has type "tuple[int, int]", variable has type "int") score, start, len = results[-1] # type: ignore[assignment] def get_prefix_func(start: int, end: int) -> _GetPrefixFunc: def get_prefix( - triple: Tuple[str, str, str], context: Optional[str] + triple: tuple[str, str, str], context: Optional[str] ) -> Generator[str, None, None]: if context is None: yield "" @@ -346,7 +347,7 @@ def add( def __remove( self, - spo: Tuple[bytes, bytes, bytes], + spo: tuple[bytes, bytes, bytes], c: bytes, quoted: bool = False, txn: Optional[Any] = None, @@ -448,11 +449,11 @@ def remove( # type: ignore[override] for i, _to_key, _ in self.__indicies_info: # NOTE on type error: variables are being # reused with a different type - # type error: Argument 1 has incompatible type "Tuple[str, str, str]"; expected "Tuple[bytes, bytes, bytes]" + # type error: Argument 1 has incompatible type "tuple[str, str, str]"; expected "tuple[bytes, bytes, bytes]" # type error: Argument 2 has incompatible type "str"; expected "bytes" i.delete(_to_key((s, p, o), c), txn=txn) # type: ignore[arg-type] else: - # type error: Argument 1 to "__remove" of "BerkeleyDB" has incompatible type "Tuple[str, str, str]"; expected "Tuple[bytes, bytes, bytes]" + # type error: Argument 1 to "__remove" of "BerkeleyDB" has incompatible type "tuple[str, str, str]"; expected "tuple[bytes, bytes, bytes]" # type error: Argument 2 to "__remove" of "BerkeleyDB" has incompatible type "str"; expected "bytes" self.__remove((s, p, o), c, txn=txn) # type: ignore[arg-type] else: @@ -477,7 +478,7 @@ def triples( context: Optional[_ContextType] = None, txn: Optional[Any] = None, ) -> Generator[ - Tuple[_TripleType, Generator[Optional[_ContextType], None, None]], + tuple[_TripleType, Generator[Optional[_ContextType], None, None]], None, None, ]: @@ -513,7 +514,7 @@ def triples( cursor.close() if key and key.startswith(prefix): contexts_value = index.get(key, txn=txn) - # type error: Incompatible types in "yield" (actual type "Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]]", expected type "Tuple[Tuple[IdentifiedNode, URIRef, Identifier], Iterator[Optional[Graph]]]") + # type error: Incompatible types in "yield" (actual type "tuple[tuple[Node, Node, Node], Generator[Node, None, None]]", expected type "tuple[tuple[IdentifiedNode, URIRef, Identifier], Iterator[Optional[Graph]]]") # NOTE on type ignore: this is needed because some context is # lost in the process of extracting triples from the database. yield results_from_key(key, subject, predicate, object, contexts_value) # type: ignore[misc] @@ -586,7 +587,7 @@ def prefix(self, namespace: URIRef) -> Optional[str]: return prefix.decode("utf-8") return None - def namespaces(self) -> Generator[Tuple[str, URIRef], None, None]: + def namespaces(self) -> Generator[tuple[str, URIRef], None, None]: cursor = self.__namespace.cursor() results = [] current = cursor.first() @@ -610,14 +611,10 @@ def contexts( s: str p: str o: str - # type error: Incompatible types in assignment (expression has type "Node", variable has type "str") - s, p, o = triple # type: ignore[assignment] - # type error: Argument 1 has incompatible type "str"; expected "Node" - s = _to_string(s) # type: ignore[arg-type] - # type error: Argument 1 has incompatible type "str"; expected "Node" - p = _to_string(p) # type: ignore[arg-type] - # type error: Argument 1 has incompatible type "str"; expected "Node" - o = _to_string(o) # type: ignore[arg-type] + _s, _p, _o = triple + s = _to_string(_s) + p = _to_string(_p) + o = _to_string(_o) contexts = self.__indicies[0].get(bb("%s^%s^%s^%s^" % ("", s, p, o))) if contexts: for c in contexts.split("^".encode("latin-1")): @@ -674,37 +671,42 @@ def __lookup( spo: _TriplePatternType, context: Optional[_ContextType], txn: Optional[Any] = None, - ) -> Tuple[db.DB, bytes, _FromKeyFunc, _ResultsFromKeyFunc]: - subject, predicate, object = spo + ) -> tuple[db.DB, bytes, _FromKeyFunc, _ResultsFromKeyFunc]: + subject, predicate, object_ = spo _to_string = self._to_string - # NOTE on type errors: this is because the same variable is used with different types. - if context is not None: - # type error: Incompatible types in assignment (expression has type "str", variable has type "Optional[Graph]") - context = _to_string(context, txn=txn) # type: ignore[assignment] + context_str: Optional[str] = ( + None if context is None else _to_string(context, txn=txn) + ) i = 0 + subject_str: Optional[str] + predicate_str: Optional[str] + object_str: Optional[str] if subject is not None: i += 1 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - subject = _to_string(subject, txn=txn) # type: ignore[assignment] + subject_str = _to_string(subject, txn=txn) + else: + subject_str = None if predicate is not None: i += 2 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - predicate = _to_string(predicate, txn=txn) # type: ignore[assignment] - if object is not None: + predicate_str = _to_string(predicate, txn=txn) + else: + predicate_str = None + if object_ is not None: i += 4 - # type error: Incompatible types in assignment (expression has type "str", variable has type "Node") - object = _to_string(object, txn=txn) # type: ignore[assignment] + object_str = _to_string(object_, txn=txn) + else: + object_str = None index, prefix_func, from_key, results_from_key = self.__lookup_dict[i] # print (subject, predicate, object), context, prefix_func, index # #DEBUG - # type error: Argument 1 has incompatible type "Tuple[Node, Node, Node]"; expected "Tuple[str, str, str]" + # type error: Argument 1 has incompatible type "tuple[Node, Node, Node]"; expected "tuple[str, str, str]" # type error: Argument 2 has incompatible type "Optional[Graph]"; expected "Optional[str]" - prefix = bb("^".join(prefix_func((subject, predicate, object), context))) # type: ignore[arg-type] + prefix = bb("^".join(prefix_func((subject_str, predicate_str, object_str), context_str))) # type: ignore[arg-type] return index, prefix, from_key, results_from_key def to_key_func(i: int) -> _ToKeyFunc: - def to_key(triple: Tuple[bytes, bytes, bytes], context: bytes) -> bytes: + def to_key(triple: tuple[bytes, bytes, bytes], context: bytes) -> bytes: "Takes a string; returns key" return "^".encode("latin-1").join( ( @@ -720,7 +722,7 @@ def to_key(triple: Tuple[bytes, bytes, bytes], context: bytes) -> bytes: def from_key_func(i: int) -> _FromKeyFunc: - def from_key(key: bytes) -> Tuple[bytes, bytes, bytes, bytes]: + def from_key(key: bytes) -> tuple[bytes, bytes, bytes, bytes]: "Takes a key; returns string" parts = key.split("^".encode("latin-1")) return ( @@ -742,7 +744,7 @@ def from_key( predicate: Optional[Node], object: Optional[Node], contexts_value: bytes, - ) -> Tuple[Tuple[Node, Node, Node], Generator[Node, None, None]]: + ) -> tuple[tuple[Node, Node, Node], Generator[Node, None, None]]: "Takes a key and subject, predicate, object; returns tuple for yield" parts = key.split("^".encode("latin-1")) if subject is None: diff --git a/rdflib/plugins/stores/memory.py b/rdflib/plugins/stores/memory.py index 7dc7c25ac..6e6435deb 100644 --- a/rdflib/plugins/stores/memory.py +++ b/rdflib/plugins/stores/memory.py @@ -2,17 +2,11 @@ # from __future__ import annotations +from collections.abc import Collection, Generator, Iterator, Mapping from typing import ( TYPE_CHECKING, Any, - Collection, - Dict, - Generator, - Iterator, - Mapping, Optional, - Set, - Tuple, Union, overload, ) @@ -59,22 +53,22 @@ def __init__( self.identifier = identifier # indexed by [subject][predicate][object] - self.__spo: Dict[_SubjectType, Dict[_PredicateType, Dict[_ObjectType, int]]] = ( + self.__spo: dict[_SubjectType, dict[_PredicateType, dict[_ObjectType, int]]] = ( {} ) # indexed by [predicate][object][subject] - self.__pos: Dict[_PredicateType, Dict[_ObjectType, Dict[_SubjectType, int]]] = ( + self.__pos: dict[_PredicateType, dict[_ObjectType, dict[_SubjectType, int]]] = ( {} ) # indexed by [predicate][object][subject] - self.__osp: Dict[_ObjectType, Dict[_SubjectType, Dict[_PredicateType, int]]] = ( + self.__osp: dict[_ObjectType, dict[_SubjectType, dict[_PredicateType, int]]] = ( {} ) - self.__namespace: Dict[str, URIRef] = {} - self.__prefix: Dict[URIRef, str] = {} + self.__namespace: dict[str, URIRef] = {} + self.__prefix: dict[URIRef, str] = {} def add( self, @@ -136,7 +130,7 @@ def triples( self, triple_pattern: _TriplePatternType, context: Optional[_ContextType] = None, - ) -> Iterator[Tuple[_TripleType, Iterator[Optional[_ContextType]]]]: + ) -> Iterator[tuple[_TripleType, Iterator[Optional[_ContextType]]]]: """A generator over all the triples matching""" subject, predicate, object = triple_pattern if subject != ANY: # subject is given @@ -219,11 +213,11 @@ def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: self.__prefix[namespace] = prefix self.__namespace[prefix] = namespace else: - # type error: Invalid index type "Optional[URIRef]" for "Dict[URIRef, str]"; expected type "URIRef" + # type error: Invalid index type "Optional[URIRef]" for "dict[URIRef, str]"; expected type "URIRef" self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce( # type: ignore[index] bound_prefix, default=prefix ) - # type error: Invalid index type "Optional[str]" for "Dict[str, URIRef]"; expected type "str" + # type error: Invalid index type "Optional[str]" for "dict[str, URIRef]"; expected type "str" self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce( # type: ignore[index] bound_namespace, default=namespace ) @@ -234,7 +228,7 @@ def namespace(self, prefix: str) -> Optional[URIRef]: def prefix(self, namespace: URIRef) -> Optional[str]: return self.__prefix.get(namespace, None) - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: + def namespaces(self) -> Iterator[tuple[str, URIRef]]: for prefix, namespace in self.__namespace.items(): yield prefix, namespace @@ -290,29 +284,29 @@ def __init__( self.identifier = identifier # indexed by [subject][predicate][object] - self.__spo: Dict[_SubjectType, Dict[_PredicateType, Dict[_ObjectType, int]]] = ( + self.__spo: dict[_SubjectType, dict[_PredicateType, dict[_ObjectType, int]]] = ( {} ) # indexed by [predicate][object][subject] - self.__pos: Dict[_PredicateType, Dict[_ObjectType, Dict[_SubjectType, int]]] = ( + self.__pos: dict[_PredicateType, dict[_ObjectType, dict[_SubjectType, int]]] = ( {} ) # indexed by [predicate][object][subject] - self.__osp: Dict[_ObjectType, Dict[_SubjectType, Dict[_PredicateType, int]]] = ( + self.__osp: dict[_ObjectType, dict[_SubjectType, dict[_PredicateType, int]]] = ( {} ) - self.__namespace: Dict[str, URIRef] = {} - self.__prefix: Dict[URIRef, str] = {} - self.__context_obj_map: Dict[str, Graph] = {} - self.__tripleContexts: Dict[_TripleType, Dict[Optional[str], bool]] = {} - self.__contextTriples: Dict[Optional[str], Set[_TripleType]] = {None: set()} + self.__namespace: dict[str, URIRef] = {} + self.__prefix: dict[URIRef, str] = {} + self.__context_obj_map: dict[str, Graph] = {} + self.__tripleContexts: dict[_TripleType, dict[Optional[str], bool]] = {} + self.__contextTriples: dict[Optional[str], set[_TripleType]] = {None: set()} # all contexts used in store (unencoded) - self.__all_contexts: Set[Graph] = set() + self.__all_contexts: set[Graph] = set() # default context information for triples - self.__defaultContexts: Optional[Dict[Optional[str], bool]] = None + self.__defaultContexts: Optional[dict[Optional[str], bool]] = None def add( self, @@ -419,7 +413,7 @@ def triples( triple_pattern: _TriplePatternType, context: Optional[_ContextType] = None, ) -> Generator[ - Tuple[_TripleType, Generator[Optional[_ContextType], None, None]], + tuple[_TripleType, Generator[Optional[_ContextType], None, None]], None, None, ]: @@ -437,7 +431,7 @@ def triples( # optimize "triple in graph" case (all parts given) elif subject is not None and predicate is not None and object_ is not None: - # type error: Incompatible types in assignment (expression has type "Tuple[Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Identifier]]", variable has type "Tuple[IdentifiedNode, IdentifiedNode, Identifier]") + # type error: Incompatible types in assignment (expression has type "tuple[Optional[IdentifiedNode], Optional[IdentifiedNode], Optional[Identifier]]", variable has type "tuple[IdentifiedNode, IdentifiedNode, Identifier]") # NOTE on type error: at this point, all elements of triple_pattern # is not None, so it has the same type as triple triple = triple_pattern # type: ignore[assignment] @@ -538,11 +532,11 @@ def bind(self, prefix: str, namespace: URIRef, override: bool = True) -> None: self.__prefix[namespace] = prefix self.__namespace[prefix] = namespace else: - # type error: Invalid index type "Optional[URIRef]" for "Dict[URIRef, str]"; expected type "URIRef" + # type error: Invalid index type "Optional[URIRef]" for "dict[URIRef, str]"; expected type "URIRef" self.__prefix[_coalesce(bound_namespace, namespace)] = _coalesce( # type: ignore[index] bound_prefix, default=prefix ) - # type error: Invalid index type "Optional[str]" for "Dict[str, URIRef]"; expected type "str" + # type error: Invalid index type "Optional[str]" for "dict[str, URIRef]"; expected type "str" # type error: Incompatible types in assignment (expression has type "Optional[URIRef]", target has type "URIRef") self.__namespace[_coalesce(bound_prefix, prefix)] = _coalesce( # type: ignore[index] bound_namespace, default=namespace @@ -554,7 +548,7 @@ def namespace(self, prefix: str) -> Optional[URIRef]: def prefix(self, namespace: URIRef) -> Optional[str]: return self.__prefix.get(namespace, None) - def namespaces(self) -> Iterator[Tuple[str, URIRef]]: + def namespaces(self) -> Iterator[tuple[str, URIRef]]: for prefix, namespace in self.__namespace.items(): yield prefix, namespace @@ -611,7 +605,7 @@ def __add_triple_context( except KeyError: # triple exists with default ctx info # start with a copy of the default ctx info - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "copy" + # type error: Item "None" of "Optional[dict[Optional[str], bool]]" has no attribute "copy" triple_context = self.__tripleContexts[triple] = ( self.__defaultContexts.copy() # type: ignore[union-attr] ) @@ -656,20 +650,20 @@ def __get_context_for_triple( ctxs = self.__tripleContexts.get(triple, self.__defaultContexts) if not skipQuoted: - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "keys" + # type error: Item "None" of "Optional[dict[Optional[str], bool]]" has no attribute "keys" return ctxs.keys() # type: ignore[union-attr] - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "items" + # type error: Item "None" of "Optional[dict[Optional[str], bool]]" has no attribute "items" return [ctx for ctx, quoted in ctxs.items() if not quoted] # type: ignore[union-attr] def __triple_has_context(self, triple: _TripleType, ctx: Optional[str]) -> bool: """return True if the triple exists in the given context""" - # type error: Unsupported right operand type for in ("Optional[Dict[Optional[str], bool]]") + # type error: Unsupported right operand type for in ("Optional[dict[Optional[str], bool]]") return ctx in self.__tripleContexts.get(triple, self.__defaultContexts) # type: ignore[operator] def __remove_triple_context(self, triple: _TripleType, ctx): """remove the context from the triple""" - # type error: Item "None" of "Optional[Dict[Optional[str], bool]]" has no attribute "copy" + # type error: Item "None" of "Optional[dict[Optional[str], bool]]" has no attribute "copy" ctxs = self.__tripleContexts.get(triple, self.__defaultContexts).copy() # type: ignore[union-attr] del ctxs[ctx] if ctxs == self.__defaultContexts: diff --git a/rdflib/plugins/stores/sparqlconnector.py b/rdflib/plugins/stores/sparqlconnector.py index e2bb83909..86f5957d1 100644 --- a/rdflib/plugins/stores/sparqlconnector.py +++ b/rdflib/plugins/stores/sparqlconnector.py @@ -4,7 +4,7 @@ import copy import logging from io import BytesIO -from typing import TYPE_CHECKING, Optional, Tuple +from typing import TYPE_CHECKING, Optional from urllib.error import HTTPError from urllib.parse import urlencode from urllib.request import Request, urlopen @@ -43,7 +43,7 @@ def __init__( update_endpoint: Optional[str] = None, returnFormat: str = "xml", # noqa: N803 method: te.Literal["GET", "POST", "POST_FORM"] = "GET", - auth: Optional[Tuple[str, str]] = None, + auth: Optional[tuple[str, str]] = None, **kwargs, ): """ diff --git a/rdflib/plugins/stores/sparqlstore.py b/rdflib/plugins/stores/sparqlstore.py index f9827cf94..38727c97e 100644 --- a/rdflib/plugins/stores/sparqlstore.py +++ b/rdflib/plugins/stores/sparqlstore.py @@ -8,29 +8,32 @@ import collections import re +from collections.abc import Callable from typing import ( TYPE_CHECKING, Any, - Callable, - Dict, - Generator, - Iterable, - Iterator, - List, - Mapping, Optional, - Tuple, Union, + cast, overload, ) from rdflib.graph import DATASET_DEFAULT_GRAPH_ID, Graph from rdflib.plugins.stores.regexmatching import NATIVE_REGEX from rdflib.store import Store -from rdflib.term import BNode, Identifier, Node, URIRef, Variable +from rdflib.term import ( + BNode, + IdentifiedNode, + Identifier, + Literal, + Node, + URIRef, + Variable, +) if TYPE_CHECKING: import typing_extensions as te # noqa: I001 + from collections.abc import Mapping, Iterator, Iterable, Generator from rdflib.graph import ( _TripleType, _ContextType, @@ -53,7 +56,7 @@ BNODE_IDENT_PATTERN = re.compile(r"(?P