diff --git a/.github/workflows/test_tap.yml b/.github/workflows/test_tap.yml index 3d1468e4..256817e3 100644 --- a/.github/workflows/test_tap.yml +++ b/.github/workflows/test_tap.yml @@ -39,7 +39,6 @@ jobs: - "3.11" - "3.10" - "3.9" - - "3.8" # run the matrix jobs one after the other so they can benefit from caching max-parallel: 1 diff --git a/.sonarcloud.properties b/.sonarcloud.properties index d2607ed4..7479be7d 100644 --- a/.sonarcloud.properties +++ b/.sonarcloud.properties @@ -1,2 +1,2 @@ -sonar.python.version=3.7, 3.8, 3.9, 3.10 +sonar.python.version=3.9, 3.10, 3.11, 3.12, 3.13 sonar.cpd.exclusions=**/* diff --git a/poetry.lock b/poetry.lock index 0051f1d9..fa3a3901 100644 --- a/poetry.lock +++ b/poetry.lock @@ -478,13 +478,13 @@ type = ["pytest-mypy"] [[package]] name = "importlib-resources" -version = "6.4.5" +version = "6.5.2" description = "Read resources from Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "importlib_resources-6.4.5-py3-none-any.whl", hash = "sha256:ac29d5f956f01d5e4bb63102a5a19957f1b9175e45649977264a1416783bb717"}, - {file = "importlib_resources-6.4.5.tar.gz", hash = "sha256:980862a1d16c9e147a59603677fa2aa5fd82b87f223b6cb870695bcfce830065"}, + {file = "importlib_resources-6.5.2-py3-none-any.whl", hash = "sha256:789cfdc3ed28c78b67a06acb8126751ced69a3d5f79c095a98298cd8a760ccec"}, + {file = "importlib_resources-6.5.2.tar.gz", hash = "sha256:185f87adef5bcc288449d98fb4fba07cea78bc036455dd44c5fc4a2fe78fed2c"}, ] [package.dependencies] @@ -559,9 +559,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} jsonschema-specifications = ">=2023.03.6" -pkgutil-resolve-name = {version = ">=1.3.10", markers = "python_version < \"3.9\""} referencing = ">=0.28.4" rpds-py = ">=0.7.1" @@ -571,17 +569,16 @@ format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339- [[package]] name = "jsonschema-specifications" -version = "2023.12.1" +version = "2024.10.1" description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, - {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, + {file = "jsonschema_specifications-2024.10.1-py3-none-any.whl", hash = "sha256:a09a0680616357d9a0ecf05c12ad234479f549239d0f5b55f3deea67475da9bf"}, + {file = "jsonschema_specifications-2024.10.1.tar.gz", hash = "sha256:0f38b83639958ce1152d02a7f062902c41c8fd20d558b0c34344292d417ae272"}, ] [package.dependencies] -importlib-resources = {version = ">=1.4.0", markers = "python_version < \"3.9\""} referencing = ">=0.31.0" [[package]] @@ -608,17 +605,6 @@ files = [ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] -[[package]] -name = "pkgutil-resolve-name" -version = "1.3.10" -description = "Resolve a name to an object." -optional = false -python-versions = ">=3.6" -files = [ - {file = "pkgutil_resolve_name-1.3.10-py3-none-any.whl", hash = "sha256:ca27cc078d25c5ad71a9de0a7a330146c4e014c2462d9af19c6b828280649c5e"}, - {file = "pkgutil_resolve_name-1.3.10.tar.gz", hash = "sha256:357d6c9e6a755653cfd78893817c0853af365dd51ec97f3d358a819373bbd174"}, -] - [[package]] name = "platformdirs" version = "4.3.6" @@ -858,114 +844,114 @@ yaml = ["pyyaml (>=6.0.1)"] [[package]] name = "rpds-py" -version = "0.20.1" +version = "0.22.3" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "rpds_py-0.20.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:a649dfd735fff086e8a9d0503a9f0c7d01b7912a333c7ae77e1515c08c146dad"}, - {file = "rpds_py-0.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f16bc1334853e91ddaaa1217045dd7be166170beec337576818461268a3de67f"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14511a539afee6f9ab492b543060c7491c99924314977a55c98bfa2ee29ce78c"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3ccb8ac2d3c71cda472b75af42818981bdacf48d2e21c36331b50b4f16930163"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c142b88039b92e7e0cb2552e8967077e3179b22359e945574f5e2764c3953dcf"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f19169781dddae7478a32301b499b2858bc52fc45a112955e798ee307e294977"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13c56de6518e14b9bf6edde23c4c39dac5b48dcf04160ea7bce8fca8397cdf86"}, - {file = "rpds_py-0.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:925d176a549f4832c6f69fa6026071294ab5910e82a0fe6c6228fce17b0706bd"}, - {file = "rpds_py-0.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:78f0b6877bfce7a3d1ff150391354a410c55d3cdce386f862926a4958ad5ab7e"}, - {file = "rpds_py-0.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3dd645e2b0dcb0fd05bf58e2e54c13875847687d0b71941ad2e757e5d89d4356"}, - {file = "rpds_py-0.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4f676e21db2f8c72ff0936f895271e7a700aa1f8d31b40e4e43442ba94973899"}, - {file = "rpds_py-0.20.1-cp310-none-win32.whl", hash = "sha256:648386ddd1e19b4a6abab69139b002bc49ebf065b596119f8f37c38e9ecee8ff"}, - {file = "rpds_py-0.20.1-cp310-none-win_amd64.whl", hash = "sha256:d9ecb51120de61e4604650666d1f2b68444d46ae18fd492245a08f53ad2b7711"}, - {file = "rpds_py-0.20.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:762703bdd2b30983c1d9e62b4c88664df4a8a4d5ec0e9253b0231171f18f6d75"}, - {file = "rpds_py-0.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0b581f47257a9fce535c4567782a8976002d6b8afa2c39ff616edf87cbeff712"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842c19a6ce894493563c3bd00d81d5100e8e57d70209e84d5491940fdb8b9e3a"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:42cbde7789f5c0bcd6816cb29808e36c01b960fb5d29f11e052215aa85497c93"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c8e9340ce5a52f95fa7d3b552b35c7e8f3874d74a03a8a69279fd5fca5dc751"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ba6f89cac95c0900d932c9efb7f0fb6ca47f6687feec41abcb1bd5e2bd45535"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a916087371afd9648e1962e67403c53f9c49ca47b9680adbeef79da3a7811b0"}, - {file = "rpds_py-0.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:200a23239781f46149e6a415f1e870c5ef1e712939fe8fa63035cd053ac2638e"}, - {file = "rpds_py-0.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:58b1d5dd591973d426cbb2da5e27ba0339209832b2f3315928c9790e13f159e8"}, - {file = "rpds_py-0.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6b73c67850ca7cae0f6c56f71e356d7e9fa25958d3e18a64927c2d930859b8e4"}, - {file = "rpds_py-0.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d8761c3c891cc51e90bc9926d6d2f59b27beaf86c74622c8979380a29cc23ac3"}, - {file = "rpds_py-0.20.1-cp311-none-win32.whl", hash = "sha256:cd945871335a639275eee904caef90041568ce3b42f402c6959b460d25ae8732"}, - {file = "rpds_py-0.20.1-cp311-none-win_amd64.whl", hash = "sha256:7e21b7031e17c6b0e445f42ccc77f79a97e2687023c5746bfb7a9e45e0921b84"}, - {file = "rpds_py-0.20.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:36785be22066966a27348444b40389f8444671630063edfb1a2eb04318721e17"}, - {file = "rpds_py-0.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:142c0a5124d9bd0e2976089484af5c74f47bd3298f2ed651ef54ea728d2ea42c"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dbddc10776ca7ebf2a299c41a4dde8ea0d8e3547bfd731cb87af2e8f5bf8962d"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15a842bb369e00295392e7ce192de9dcbf136954614124a667f9f9f17d6a216f"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be5ef2f1fc586a7372bfc355986226484e06d1dc4f9402539872c8bb99e34b01"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbcf360c9e3399b056a238523146ea77eeb2a596ce263b8814c900263e46031a"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ecd27a66740ffd621d20b9a2f2b5ee4129a56e27bfb9458a3bcc2e45794c96cb"}, - {file = "rpds_py-0.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0b937b2a1988f184a3e9e577adaa8aede21ec0b38320d6009e02bd026db04fa"}, - {file = "rpds_py-0.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6889469bfdc1eddf489729b471303739bf04555bb151fe8875931f8564309afc"}, - {file = "rpds_py-0.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:19b73643c802f4eaf13d97f7855d0fb527fbc92ab7013c4ad0e13a6ae0ed23bd"}, - {file = "rpds_py-0.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3c6afcf2338e7f374e8edc765c79fbcb4061d02b15dd5f8f314a4af2bdc7feb5"}, - {file = "rpds_py-0.20.1-cp312-none-win32.whl", hash = "sha256:dc73505153798c6f74854aba69cc75953888cf9866465196889c7cdd351e720c"}, - {file = "rpds_py-0.20.1-cp312-none-win_amd64.whl", hash = "sha256:8bbe951244a838a51289ee53a6bae3a07f26d4e179b96fc7ddd3301caf0518eb"}, - {file = "rpds_py-0.20.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:6ca91093a4a8da4afae7fe6a222c3b53ee4eef433ebfee4d54978a103435159e"}, - {file = "rpds_py-0.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b9c2fe36d1f758b28121bef29ed1dee9b7a2453e997528e7d1ac99b94892527c"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f009c69bc8c53db5dfab72ac760895dc1f2bc1b62ab7408b253c8d1ec52459fc"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6740a3e8d43a32629bb9b009017ea5b9e713b7210ba48ac8d4cb6d99d86c8ee8"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:32b922e13d4c0080d03e7b62991ad7f5007d9cd74e239c4b16bc85ae8b70252d"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe00a9057d100e69b4ae4a094203a708d65b0f345ed546fdef86498bf5390982"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49fe9b04b6fa685bd39237d45fad89ba19e9163a1ccaa16611a812e682913496"}, - {file = "rpds_py-0.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aa7ac11e294304e615b43f8c441fee5d40094275ed7311f3420d805fde9b07b4"}, - {file = "rpds_py-0.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aa97af1558a9bef4025f8f5d8c60d712e0a3b13a2fe875511defc6ee77a1ab7"}, - {file = "rpds_py-0.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:483b29f6f7ffa6af845107d4efe2e3fa8fb2693de8657bc1849f674296ff6a5a"}, - {file = "rpds_py-0.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:37fe0f12aebb6a0e3e17bb4cd356b1286d2d18d2e93b2d39fe647138458b4bcb"}, - {file = "rpds_py-0.20.1-cp313-none-win32.whl", hash = "sha256:a624cc00ef2158e04188df5e3016385b9353638139a06fb77057b3498f794782"}, - {file = "rpds_py-0.20.1-cp313-none-win_amd64.whl", hash = "sha256:b71b8666eeea69d6363248822078c075bac6ed135faa9216aa85f295ff009b1e"}, - {file = "rpds_py-0.20.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5b48e790e0355865197ad0aca8cde3d8ede347831e1959e158369eb3493d2191"}, - {file = "rpds_py-0.20.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3e310838a5801795207c66c73ea903deda321e6146d6f282e85fa7e3e4854804"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2249280b870e6a42c0d972339e9cc22ee98730a99cd7f2f727549af80dd5a963"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e79059d67bea28b53d255c1437b25391653263f0e69cd7dec170d778fdbca95e"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2b431c777c9653e569986ecf69ff4a5dba281cded16043d348bf9ba505486f36"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da584ff96ec95e97925174eb8237e32f626e7a1a97888cdd27ee2f1f24dd0ad8"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a0629ec053fc013808a85178524e3cb63a61dbc35b22499870194a63578fb9"}, - {file = "rpds_py-0.20.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fbf15aff64a163db29a91ed0868af181d6f68ec1a3a7d5afcfe4501252840bad"}, - {file = "rpds_py-0.20.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:07924c1b938798797d60c6308fa8ad3b3f0201802f82e4a2c41bb3fafb44cc28"}, - {file = "rpds_py-0.20.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:4a5a844f68776a7715ecb30843b453f07ac89bad393431efbf7accca3ef599c1"}, - {file = "rpds_py-0.20.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:518d2ca43c358929bf08f9079b617f1c2ca6e8848f83c1225c88caeac46e6cbc"}, - {file = "rpds_py-0.20.1-cp38-none-win32.whl", hash = "sha256:3aea7eed3e55119635a74bbeb80b35e776bafccb70d97e8ff838816c124539f1"}, - {file = "rpds_py-0.20.1-cp38-none-win_amd64.whl", hash = "sha256:7dca7081e9a0c3b6490a145593f6fe3173a94197f2cb9891183ef75e9d64c425"}, - {file = "rpds_py-0.20.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:b41b6321805c472f66990c2849e152aff7bc359eb92f781e3f606609eac877ad"}, - {file = "rpds_py-0.20.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a90c373ea2975519b58dece25853dbcb9779b05cc46b4819cb1917e3b3215b6"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d4477bcb9fbbd7b5b0e4a5d9b493e42026c0bf1f06f723a9353f5153e75d30"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:84b8382a90539910b53a6307f7c35697bc7e6ffb25d9c1d4e998a13e842a5e83"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4888e117dd41b9d34194d9e31631af70d3d526efc363085e3089ab1a62c32ed1"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5265505b3d61a0f56618c9b941dc54dc334dc6e660f1592d112cd103d914a6db"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e75ba609dba23f2c95b776efb9dd3f0b78a76a151e96f96cc5b6b1b0004de66f"}, - {file = "rpds_py-0.20.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1791ff70bc975b098fe6ecf04356a10e9e2bd7dc21fa7351c1742fdeb9b4966f"}, - {file = "rpds_py-0.20.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d126b52e4a473d40232ec2052a8b232270ed1f8c9571aaf33f73a14cc298c24f"}, - {file = "rpds_py-0.20.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c14937af98c4cc362a1d4374806204dd51b1e12dded1ae30645c298e5a5c4cb1"}, - {file = "rpds_py-0.20.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3d089d0b88996df627693639d123c8158cff41c0651f646cd8fd292c7da90eaf"}, - {file = "rpds_py-0.20.1-cp39-none-win32.whl", hash = "sha256:653647b8838cf83b2e7e6a0364f49af96deec64d2a6578324db58380cff82aca"}, - {file = "rpds_py-0.20.1-cp39-none-win_amd64.whl", hash = "sha256:fa41a64ac5b08b292906e248549ab48b69c5428f3987b09689ab2441f267d04d"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a07ced2b22f0cf0b55a6a510078174c31b6d8544f3bc00c2bcee52b3d613f74"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:68cb0a499f2c4a088fd2f521453e22ed3527154136a855c62e148b7883b99f9a"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fa3060d885657abc549b2a0f8e1b79699290e5d83845141717c6c90c2df38311"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95f3b65d2392e1c5cec27cff08fdc0080270d5a1a4b2ea1d51d5f4a2620ff08d"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2cc3712a4b0b76a1d45a9302dd2f53ff339614b1c29603a911318f2357b04dd2"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d4eea0761e37485c9b81400437adb11c40e13ef513375bbd6973e34100aeb06"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f5179583d7a6cdb981151dd349786cbc318bab54963a192692d945dd3f6435d"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fbb0ffc754490aff6dabbf28064be47f0f9ca0b9755976f945214965b3ace7e"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a94e52537a0e0a85429eda9e49f272ada715506d3b2431f64b8a3e34eb5f3e75"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:92b68b79c0da2a980b1c4197e56ac3dd0c8a149b4603747c4378914a68706979"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:93da1d3db08a827eda74356f9f58884adb254e59b6664f64cc04cdff2cc19b0d"}, - {file = "rpds_py-0.20.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:754bbed1a4ca48479e9d4182a561d001bbf81543876cdded6f695ec3d465846b"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ca449520e7484534a2a44faf629362cae62b660601432d04c482283c47eaebab"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:9c4cb04a16b0f199a8c9bf807269b2f63b7b5b11425e4a6bd44bd6961d28282c"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb63804105143c7e24cee7db89e37cb3f3941f8e80c4379a0b355c52a52b6780"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:55cd1fa4ecfa6d9f14fbd97ac24803e6f73e897c738f771a9fe038f2f11ff07c"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f8f741b6292c86059ed175d80eefa80997125b7c478fb8769fd9ac8943a16c0"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fc212779bf8411667234b3cdd34d53de6c2b8b8b958e1e12cb473a5f367c338"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ad56edabcdb428c2e33bbf24f255fe2b43253b7d13a2cdbf05de955217313e6"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:0a3a1e9ee9728b2c1734f65d6a1d376c6f2f6fdcc13bb007a08cc4b1ff576dc5"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e13de156137b7095442b288e72f33503a469aa1980ed856b43c353ac86390519"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:07f59760ef99f31422c49038964b31c4dfcfeb5d2384ebfc71058a7c9adae2d2"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:59240685e7da61fb78f65a9f07f8108e36a83317c53f7b276b4175dc44151684"}, - {file = "rpds_py-0.20.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:83cba698cfb3c2c5a7c3c6bac12fe6c6a51aae69513726be6411076185a8b24a"}, - {file = "rpds_py-0.20.1.tar.gz", hash = "sha256:e1791c4aabd117653530dccd24108fa03cc6baf21f58b950d0a73c3b3b29a350"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:6c7b99ca52c2c1752b544e310101b98a659b720b21db00e65edca34483259967"}, + {file = "rpds_py-0.22.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:be2eb3f2495ba669d2a985f9b426c1797b7d48d6963899276d22f23e33d47e37"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70eb60b3ae9245ddea20f8a4190bd79c705a22f8028aaf8bbdebe4716c3fab24"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4041711832360a9b75cfb11b25a6a97c8fb49c07b8bd43d0d02b45d0b499a4ff"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64607d4cbf1b7e3c3c8a14948b99345eda0e161b852e122c6bb71aab6d1d798c"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e69b0a0e2537f26d73b4e43ad7bc8c8efb39621639b4434b76a3de50c6966e"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc27863442d388870c1809a87507727b799c8460573cfbb6dc0eeaef5a11b5ec"}, + {file = "rpds_py-0.22.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e79dd39f1e8c3504be0607e5fc6e86bb60fe3584bec8b782578c3b0fde8d932c"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e0fa2d4ec53dc51cf7d3bb22e0aa0143966119f42a0c3e4998293a3dd2856b09"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fda7cb070f442bf80b642cd56483b5548e43d366fe3f39b98e67cce780cded00"}, + {file = "rpds_py-0.22.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:cff63a0272fcd259dcc3be1657b07c929c466b067ceb1c20060e8d10af56f5bf"}, + {file = "rpds_py-0.22.3-cp310-cp310-win32.whl", hash = "sha256:9bd7228827ec7bb817089e2eb301d907c0d9827a9e558f22f762bb690b131652"}, + {file = "rpds_py-0.22.3-cp310-cp310-win_amd64.whl", hash = "sha256:9beeb01d8c190d7581a4d59522cd3d4b6887040dcfc744af99aa59fef3e041a8"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d20cfb4e099748ea39e6f7b16c91ab057989712d31761d3300d43134e26e165f"}, + {file = "rpds_py-0.22.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:68049202f67380ff9aa52f12e92b1c30115f32e6895cd7198fa2a7961621fc5a"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb4f868f712b2dd4bcc538b0a0c1f63a2b1d584c925e69a224d759e7070a12d5"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bc51abd01f08117283c5ebf64844a35144a0843ff7b2983e0648e4d3d9f10dbb"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f3cec041684de9a4684b1572fe28c7267410e02450f4561700ca5a3bc6695a2"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ef9d9da710be50ff6809fed8f1963fecdfecc8b86656cadfca3bc24289414b0"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59f4a79c19232a5774aee369a0c296712ad0e77f24e62cad53160312b1c1eaa1"}, + {file = "rpds_py-0.22.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a60bce91f81ddaac922a40bbb571a12c1070cb20ebd6d49c48e0b101d87300d"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e89391e6d60251560f0a8f4bd32137b077a80d9b7dbe6d5cab1cd80d2746f648"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3fb866d9932a3d7d0c82da76d816996d1667c44891bd861a0f97ba27e84fc74"}, + {file = "rpds_py-0.22.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1352ae4f7c717ae8cba93421a63373e582d19d55d2ee2cbb184344c82d2ae55a"}, + {file = "rpds_py-0.22.3-cp311-cp311-win32.whl", hash = "sha256:b0b4136a252cadfa1adb705bb81524eee47d9f6aab4f2ee4fa1e9d3cd4581f64"}, + {file = "rpds_py-0.22.3-cp311-cp311-win_amd64.whl", hash = "sha256:8bd7c8cfc0b8247c8799080fbff54e0b9619e17cdfeb0478ba7295d43f635d7c"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:27e98004595899949bd7a7b34e91fa7c44d7a97c40fcaf1d874168bb652ec67e"}, + {file = "rpds_py-0.22.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1978d0021e943aae58b9b0b196fb4895a25cc53d3956b8e35e0b7682eefb6d56"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:655ca44a831ecb238d124e0402d98f6212ac527a0ba6c55ca26f616604e60a45"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:feea821ee2a9273771bae61194004ee2fc33f8ec7db08117ef9147d4bbcbca8e"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:22bebe05a9ffc70ebfa127efbc429bc26ec9e9b4ee4d15a740033efda515cf3d"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3af6e48651c4e0d2d166dc1b033b7042ea3f871504b6805ba5f4fe31581d8d38"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e67ba3c290821343c192f7eae1d8fd5999ca2dc99994114643e2f2d3e6138b15"}, + {file = "rpds_py-0.22.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:02fbb9c288ae08bcb34fb41d516d5eeb0455ac35b5512d03181d755d80810059"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f56a6b404f74ab372da986d240e2e002769a7d7102cc73eb238a4f72eec5284e"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0a0461200769ab3b9ab7e513f6013b7a97fdeee41c29b9db343f3c5a8e2b9e61"}, + {file = "rpds_py-0.22.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8633e471c6207a039eff6aa116e35f69f3156b3989ea3e2d755f7bc41754a4a7"}, + {file = "rpds_py-0.22.3-cp312-cp312-win32.whl", hash = "sha256:593eba61ba0c3baae5bc9be2f5232430453fb4432048de28399ca7376de9c627"}, + {file = "rpds_py-0.22.3-cp312-cp312-win_amd64.whl", hash = "sha256:d115bffdd417c6d806ea9069237a4ae02f513b778e3789a359bc5856e0404cc4"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:ea7433ce7e4bfc3a85654aeb6747babe3f66eaf9a1d0c1e7a4435bbdf27fea84"}, + {file = "rpds_py-0.22.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6dd9412824c4ce1aca56c47b0991e65bebb7ac3f4edccfd3f156150c96a7bf25"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:20070c65396f7373f5df4005862fa162db5d25d56150bddd0b3e8214e8ef45b4"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0b09865a9abc0ddff4e50b5ef65467cd94176bf1e0004184eb915cbc10fc05c5"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3453e8d41fe5f17d1f8e9c383a7473cd46a63661628ec58e07777c2fff7196dc"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f5d36399a1b96e1a5fdc91e0522544580dbebeb1f77f27b2b0ab25559e103b8b"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:009de23c9c9ee54bf11303a966edf4d9087cd43a6003672e6aa7def643d06518"}, + {file = "rpds_py-0.22.3-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1aef18820ef3e4587ebe8b3bc9ba6e55892a6d7b93bac6d29d9f631a3b4befbd"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f60bd8423be1d9d833f230fdbccf8f57af322d96bcad6599e5a771b151398eb2"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:62d9cfcf4948683a18a9aff0ab7e1474d407b7bab2ca03116109f8464698ab16"}, + {file = "rpds_py-0.22.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9253fc214112405f0afa7db88739294295f0e08466987f1d70e29930262b4c8f"}, + {file = "rpds_py-0.22.3-cp313-cp313-win32.whl", hash = "sha256:fb0ba113b4983beac1a2eb16faffd76cb41e176bf58c4afe3e14b9c681f702de"}, + {file = "rpds_py-0.22.3-cp313-cp313-win_amd64.whl", hash = "sha256:c58e2339def52ef6b71b8f36d13c3688ea23fa093353f3a4fee2556e62086ec9"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:f82a116a1d03628a8ace4859556fb39fd1424c933341a08ea3ed6de1edb0283b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3dfcbc95bd7992b16f3f7ba05af8a64ca694331bd24f9157b49dadeeb287493b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:59259dc58e57b10e7e18ce02c311804c10c5a793e6568f8af4dead03264584d1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5725dd9cc02068996d4438d397e255dcb1df776b7ceea3b9cb972bdb11260a83"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99b37292234e61325e7a5bb9689e55e48c3f5f603af88b1642666277a81f1fbd"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:27b1d3b3915a99208fee9ab092b8184c420f2905b7d7feb4aeb5e4a9c509b8a1"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f612463ac081803f243ff13cccc648578e2279295048f2a8d5eb430af2bae6e3"}, + {file = "rpds_py-0.22.3-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f73d3fef726b3243a811121de45193c0ca75f6407fe66f3f4e183c983573e130"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:3f21f0495edea7fdbaaa87e633a8689cd285f8f4af5c869f27bc8074638ad69c"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:1e9663daaf7a63ceccbbb8e3808fe90415b0757e2abddbfc2e06c857bf8c5e2b"}, + {file = "rpds_py-0.22.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a76e42402542b1fae59798fab64432b2d015ab9d0c8c47ba7addddbaf7952333"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win32.whl", hash = "sha256:69803198097467ee7282750acb507fba35ca22cc3b85f16cf45fb01cb9097730"}, + {file = "rpds_py-0.22.3-cp313-cp313t-win_amd64.whl", hash = "sha256:f5cf2a0c2bdadf3791b5c205d55a37a54025c6e18a71c71f82bb536cf9a454bf"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:378753b4a4de2a7b34063d6f95ae81bfa7b15f2c1a04a9518e8644e81807ebea"}, + {file = "rpds_py-0.22.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3445e07bf2e8ecfeef6ef67ac83de670358abf2996916039b16a218e3d95e97e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b2513ba235829860b13faa931f3b6846548021846ac808455301c23a101689d"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eaf16ae9ae519a0e237a0f528fd9f0197b9bb70f40263ee57ae53c2b8d48aeb3"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:583f6a1993ca3369e0f80ba99d796d8e6b1a3a2a442dd4e1a79e652116413091"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4617e1915a539a0d9a9567795023de41a87106522ff83fbfaf1f6baf8e85437e"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c150c7a61ed4a4f4955a96626574e9baf1adf772c2fb61ef6a5027e52803543"}, + {file = "rpds_py-0.22.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2fa4331c200c2521512595253f5bb70858b90f750d39b8cbfd67465f8d1b596d"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:214b7a953d73b5e87f0ebece4a32a5bd83c60a3ecc9d4ec8f1dca968a2d91e99"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:f47ad3d5f3258bd7058d2d506852217865afefe6153a36eb4b6928758041d831"}, + {file = "rpds_py-0.22.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f276b245347e6e36526cbd4a266a417796fc531ddf391e43574cf6466c492520"}, + {file = "rpds_py-0.22.3-cp39-cp39-win32.whl", hash = "sha256:bbb232860e3d03d544bc03ac57855cd82ddf19c7a07651a7c0fdb95e9efea8b9"}, + {file = "rpds_py-0.22.3-cp39-cp39-win_amd64.whl", hash = "sha256:cfbc454a2880389dbb9b5b398e50d439e2e58669160f27b60e5eca11f68ae17c"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:d48424e39c2611ee1b84ad0f44fb3b2b53d473e65de061e3f460fc0be5f1939d"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:24e8abb5878e250f2eb0d7859a8e561846f98910326d06c0d51381fed59357bd"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b232061ca880db21fa14defe219840ad9b74b6158adb52ddf0e87bead9e8493"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac0a03221cdb5058ce0167ecc92a8c89e8d0decdc9e99a2ec23380793c4dcb96"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb0c341fa71df5a4595f9501df4ac5abfb5a09580081dffbd1ddd4654e6e9123"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bf9db5488121b596dbfc6718c76092fda77b703c1f7533a226a5a9f65248f8ad"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0b8db6b5b2d4491ad5b6bdc2bc7c017eec108acbf4e6785f42a9eb0ba234f4c9"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3d504047aba448d70cf6fa22e06cb09f7cbd761939fdd47604f5e007675c24e"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:e61b02c3f7a1e0b75e20c3978f7135fd13cb6cf551bf4a6d29b999a88830a338"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:e35ba67d65d49080e8e5a1dd40101fccdd9798adb9b050ff670b7d74fa41c566"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:26fd7cac7dd51011a245f29a2cc6489c4608b5a8ce8d75661bb4a1066c52dfbe"}, + {file = "rpds_py-0.22.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:177c7c0fce2855833819c98e43c262007f42ce86651ffbb84f37883308cb0e7d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bb47271f60660803ad11f4c61b42242b8c1312a31c98c578f79ef9387bbde21c"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:70fb28128acbfd264eda9bf47015537ba3fe86e40d046eb2963d75024be4d055"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:44d61b4b7d0c2c9ac019c314e52d7cbda0ae31078aabd0f22e583af3e0d79723"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f0e260eaf54380380ac3808aa4ebe2d8ca28b9087cf411649f96bad6900c728"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b25bc607423935079e05619d7de556c91fb6adeae9d5f80868dde3468657994b"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fb6116dfb8d1925cbdb52595560584db42a7f664617a1f7d7f6e32f138cdf37d"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a63cbdd98acef6570c62b92a1e43266f9e8b21e699c363c0fef13bd530799c11"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2b8f60e1b739a74bab7e01fcbe3dddd4657ec685caa04681df9d562ef15b625f"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:2e8b55d8517a2fda8d95cb45d62a5a8bbf9dd0ad39c5b25c8833efea07b880ca"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:2de29005e11637e7a2361fa151f780ff8eb2543a0da1413bb951e9f14b699ef3"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:666ecce376999bf619756a24ce15bb14c5bfaf04bf00abc7e663ce17c3f34fe7"}, + {file = "rpds_py-0.22.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:5246b14ca64a8675e0a7161f7af68fe3e910e6b90542b4bfb5439ba752191df6"}, + {file = "rpds_py-0.22.3.tar.gz", hash = "sha256:e32fee8ab45d3c2db6da19a5323bc3362237c8b653c70194414b892fd06a080d"}, ] [[package]] @@ -983,17 +969,6 @@ files = [ doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -[[package]] -name = "simpleeval" -version = "0.9.13" -description = "A simple, safe single expression evaluator library." -optional = false -python-versions = "*" -files = [ - {file = "simpleeval-0.9.13-py2.py3-none-any.whl", hash = "sha256:22a2701a5006e4188d125d34accf2405c2c37c93f6b346f2484b6422415ae54a"}, - {file = "simpleeval-0.9.13.tar.gz", hash = "sha256:4a30f9cc01825fe4c719c785e3762623e350c4840d5e6855c2a8496baaa65fac"}, -] - [[package]] name = "simpleeval" version = "1.0.3" @@ -1153,10 +1128,7 @@ PyYAML = ">=6.0" referencing = ">=0.30.0" requests = ">=2.25.1" setuptools = "<=70.3.0" -simpleeval = [ - {version = ">=0.9.13,<1.0.1 || >1.0.1", markers = "python_version >= \"3.9\""}, - {version = ">=0.9.13,<1", markers = "python_version < \"3.9\""}, -] +simpleeval = {version = ">=0.9.13,<1.0.1 || >1.0.1", markers = "python_version >= \"3.9\""} simplejson = ">=3.17.6" sqlalchemy = ">=1.4,<3.0" typing-extensions = ">=4.5.0" @@ -1416,13 +1388,13 @@ six = "*" [[package]] name = "urllib3" -version = "2.2.3" +version = "2.3.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, - {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, + {file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"}, + {file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"}, ] [package.extras] @@ -1433,13 +1405,13 @@ zstd = ["zstandard (>=0.18.0)"] [[package]] name = "zipp" -version = "3.20.2" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.2-py3-none-any.whl", hash = "sha256:a817ac80d6cf4b23bf7f2828b7cabf326f15a001bea8b1f9b49631780ba28350"}, - {file = "zipp-3.20.2.tar.gz", hash = "sha256:bc9eb26f4506fda01b81bcde0ca78103b6e62f991b381fec825435c836edbc29"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -1452,5 +1424,5 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" -python-versions = ">=3.8" -content-hash = "c08fad5f3d548b0622d5889978f7107be1a097918356e9be156d9214a238912b" +python-versions = ">=3.9" +content-hash = "ce5fd68b46bfbb3d9f6c562d7b66a8b64a31e008e9a2f2080a58755835065a37" diff --git a/pyproject.toml b/pyproject.toml index 0b971c9c..aede871e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,7 +11,6 @@ classifiers = [ "Intended Audience :: Developers", "License :: OSI Approved :: Apache Software License", "Operating System :: OS Independent", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", @@ -28,7 +27,7 @@ classifiers = [ beautifulsoup4 = "~=4.12.0" nested-lookup = "~=0.2.25" PyJWT = "2.9.0" -python = ">=3.8" +python = ">=3.9" python-dateutil = "~=2.9" requests = "~=2.32.3" # For local SDK dev: @@ -62,17 +61,21 @@ markers = [ ] [tool.ruff] -target-version = "py38" +target-version = "py39" [tool.ruff.lint] ignore = [] select = [ - "F", # Pyflakes - "E", # pycodestyle (errors) - "W", # pycodestyle (warnings) - "I", # isort - "UP", # pyupgrade - "FA", # flake8-future-annotations - "SIM", # flake8-simplify - "RUF", # Ruff-specific rules + "F", # Pyflakes + "E", # pycodestyle (errors) + "W", # pycodestyle (warnings) + "I", # isort + "UP", # pyupgrade + "DTZ", # flake8-datetimez + "FA", # flake8-future-annotations + "SIM", # flake8-simplify + "TC", # flake8-type-checking + "PERF", # Perflint + "FURB", # refurb + "RUF", # Ruff-specific rules ] diff --git a/tap_github/authenticator.py b/tap_github/authenticator.py index 10cead25..0ca79b14 100644 --- a/tap_github/authenticator.py +++ b/tap_github/authenticator.py @@ -8,12 +8,14 @@ from datetime import datetime, timedelta, timezone from os import environ from random import choice, shuffle -from typing import Any +from typing import TYPE_CHECKING, Any import jwt import requests from singer_sdk.authenticators import APIAuthenticatorBase -from singer_sdk.streams import RESTStream + +if TYPE_CHECKING: + from singer_sdk.streams import RESTStream class TokenManager: @@ -307,7 +309,7 @@ def prepare_tokens(self) -> list[TokenManager]: ) if app_token_manager.is_valid_token(): app_token_managers.append(app_token_manager) - except ValueError as e: + except ValueError as e: # noqa: PERF203 self.logger.warning( f"An error was thrown while preparing an app token: {e}" ) diff --git a/tap_github/client.py b/tap_github/client.py index b0de19ad..2d106413 100644 --- a/tap_github/client.py +++ b/tap_github/client.py @@ -7,11 +7,9 @@ import random import time from types import FrameType -from typing import Any, ClassVar, Iterable, cast +from typing import TYPE_CHECKING, Any, ClassVar, cast from urllib.parse import parse_qs, urlparse -import requests -from backoff.types import Details from dateutil.parser import parse from nested_lookup import nested_lookup from singer_sdk.exceptions import FatalAPIError, RetriableAPIError @@ -20,6 +18,12 @@ from tap_github.authenticator import GitHubTokenAuthenticator +if TYPE_CHECKING: + from collections.abc import Iterable + + import requests + from backoff.types import Details + EMPTY_REPO_ERROR_STATUS = 409 diff --git a/tap_github/organization_streams.py b/tap_github/organization_streams.py index 0cb3fa35..66950b1f 100644 --- a/tap_github/organization_streams.py +++ b/tap_github/organization_streams.py @@ -2,12 +2,15 @@ from __future__ import annotations -from typing import Any, ClassVar, Iterable +from typing import TYPE_CHECKING, Any, ClassVar from singer_sdk import typing as th # JSON Schema typing helpers from tap_github.client import GitHubRestStream +if TYPE_CHECKING: + from collections.abc import Iterable + class OrganizationStream(GitHubRestStream): """Defines a GitHub Organization Stream. diff --git a/tap_github/repository_streams.py b/tap_github/repository_streams.py index a3b8ee67..ddbff242 100644 --- a/tap_github/repository_streams.py +++ b/tap_github/repository_streams.py @@ -2,10 +2,9 @@ from __future__ import annotations -from typing import Any, ClassVar, Iterable +from typing import TYPE_CHECKING, Any, ClassVar from urllib.parse import parse_qs, urlparse -import requests from dateutil.parser import parse from singer_sdk import typing as th # JSON Schema typing helpers from singer_sdk.exceptions import FatalAPIError @@ -21,6 +20,11 @@ ) from tap_github.scraping import scrape_dependents, scrape_metrics +if TYPE_CHECKING: + from collections.abc import Iterable + + import requests + class RepositoryStream(GitHubRestStream): """Defines 'Repository' stream.""" diff --git a/tap_github/scraping.py b/tap_github/scraping.py index f6e5e06d..9e736129 100644 --- a/tap_github/scraping.py +++ b/tap_github/scraping.py @@ -9,11 +9,15 @@ import re import time from datetime import datetime, timezone -from typing import Any, Iterable, cast +from typing import TYPE_CHECKING, Any, cast from urllib.parse import urlparse import requests -from bs4 import NavigableString, Tag + +if TYPE_CHECKING: + from collections.abc import Iterable + + from bs4 import NavigableString, Tag used_by_regex = re.compile(" {3}Used by ") contributors_regex = re.compile(" {3}Contributors ") @@ -30,12 +34,7 @@ def scrape_dependents( # Navigate through Package toggle if present base_url = urlparse(response.url).hostname or "github.com" options = soup.find_all("a", class_="select-menu-item") - links = [] - if len(options) > 0: - for link in options: - links.append(link["href"]) - else: - links.append(response.url) + links = [link["href"] for link in options] if len(options) > 0 else [response.url] logger.debug(links) diff --git a/tap_github/streams.py b/tap_github/streams.py index 2475bac8..c8316e0a 100644 --- a/tap_github/streams.py +++ b/tap_github/streams.py @@ -1,8 +1,7 @@ from __future__ import annotations from enum import Enum - -from singer_sdk.streams.core import Stream +from typing import TYPE_CHECKING from tap_github.organization_streams import ( OrganizationStream, @@ -52,6 +51,9 @@ ) from tap_github.user_streams import StarredStream, UserContributedToStream, UserStream +if TYPE_CHECKING: + from singer_sdk.streams.core import Stream + class Streams(Enum): """ diff --git a/tap_github/tests/test_authenticator.py b/tap_github/tests/test_authenticator.py index 8bc2261d..672634dd 100644 --- a/tap_github/tests/test_authenticator.py +++ b/tap_github/tests/test_authenticator.py @@ -154,9 +154,12 @@ def test_initialization_with_malformed_env_key(self): AppTokenManager("12345key\\ncontent") def test_generate_token_with_invalid_credentials(self): - with patch.object(AppTokenManager, "is_valid_token", return_value=False), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("some_token", MagicMock()), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=False), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("some_token", MagicMock()), + ), ): token_manager = AppTokenManager("12345;;key\\ncontent;;67890") assert token_manager.token is None @@ -164,9 +167,12 @@ def test_generate_token_with_invalid_credentials(self): def test_successful_token_generation(self): token_time = MagicMock() - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", token_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", token_time), + ), ): token_manager = AppTokenManager("12345;;key\\ncontent;;67890") token_manager.claim_token() @@ -176,9 +182,12 @@ def test_successful_token_generation(self): def test_has_calls_remaining_regenerates_a_token_if_close_to_expiry(self): unexpired_time = _now() + timedelta(days=1) expired_time = _now() - timedelta(days=1) - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): mock_response_headers = { "X-RateLimit-Limit": "5000", @@ -205,11 +214,14 @@ def test_has_calls_remaining_regenerates_a_token_if_close_to_expiry(self): def test_has_calls_remaining_logs_warning_if_token_regeneration_fails(self): unexpired_time = _now() + timedelta(days=1) expired_time = _now() - timedelta(days=1) - with patch.object( - AppTokenManager, "is_valid_token", return_value=True - ) as mock_is_valid, patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object( + AppTokenManager, "is_valid_token", return_value=True + ) as mock_is_valid, + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): mock_response_headers = { "X-RateLimit-Limit": "5000", @@ -233,18 +245,24 @@ def test_has_calls_remaining_logs_warning_if_token_regeneration_fails(self): def test_has_calls_remaining_succeeds_if_token_new_and_never_used(self): unexpired_time = _now() + timedelta(days=1) - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): token_manager = AppTokenManager("12345;;key\\ncontent;;67890") assert token_manager.has_calls_remaining() def test_has_calls_remaining_succeeds_if_time_and_requests_left(self): unexpired_time = _now() + timedelta(days=1) - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): mock_response_headers = { "X-RateLimit-Limit": "5000", @@ -260,9 +278,12 @@ def test_has_calls_remaining_succeeds_if_time_and_requests_left(self): def test_has_calls_remaining_succeeds_if_time_left_and_reset_time_reached(self): unexpired_time = _now() + timedelta(days=1) - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): mock_response_headers = { "X-RateLimit-Limit": "5000", @@ -282,9 +303,12 @@ def test_has_calls_remaining_fails_if_time_left_and_few_calls_remaining_and_rese self, ): unexpired_time = _now() + timedelta(days=1) - with patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("valid_token", unexpired_time), + with ( + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("valid_token", unexpired_time), + ), ): mock_response_headers = { "X-RateLimit-Limit": "5000", @@ -314,20 +338,28 @@ def mock_stream(): class TestGitHubTokenAuthenticator: def test_prepare_tokens_returns_empty_if_none_found(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, "get_env", return_value={"GITHUB_TLJKJFDS": "gt1"} - ), patch.object(PersonalTokenManager, "is_valid_token", return_value=True): + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={"GITHUB_TLJKJFDS": "gt1"}, + ), + patch.object(PersonalTokenManager, "is_valid_token", return_value=True), + ): auth = GitHubTokenAuthenticator(stream=mock_stream) token_managers = auth.prepare_tokens() assert len(token_managers) == 0 def test_config_auth_token_only(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"OTHER_TOKEN": "blah", "NOT_THE_RIGHT_TOKEN": "meh"}, - ), patch.object(PersonalTokenManager, "is_valid_token", return_value=True): + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={"OTHER_TOKEN": "blah", "NOT_THE_RIGHT_TOKEN": "meh"}, + ), + patch.object(PersonalTokenManager, "is_valid_token", return_value=True), + ): stream = mock_stream stream.config.update({"auth_token": "gt5"}) auth = GitHubTokenAuthenticator(stream=stream) @@ -337,11 +369,14 @@ def test_config_auth_token_only(self, mock_stream): assert token_managers[0].token == "gt5" def test_config_additional_auth_tokens_only(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"OTHER_TOKEN": "blah", "NOT_THE_RIGHT_TOKEN": "meh"}, - ), patch.object(PersonalTokenManager, "is_valid_token", return_value=True): + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={"OTHER_TOKEN": "blah", "NOT_THE_RIGHT_TOKEN": "meh"}, + ), + patch.object(PersonalTokenManager, "is_valid_token", return_value=True), + ): stream = mock_stream stream.config.update({"additional_auth_tokens": ["gt7", "gt8", "gt9"]}) auth = GitHubTokenAuthenticator(stream=stream) @@ -351,15 +386,18 @@ def test_config_additional_auth_tokens_only(self, mock_stream): assert sorted({tm.token for tm in token_managers}) == ["gt7", "gt8", "gt9"] def test_env_personal_tokens_only(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={ - "GITHUB_TOKEN1": "gt1", - "GITHUB_TOKENxyz": "gt2", - "OTHER_TOKEN": "blah", - }, - ), patch.object(PersonalTokenManager, "is_valid_token", return_value=True): + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_TOKENxyz": "gt2", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(PersonalTokenManager, "is_valid_token", return_value=True), + ): auth = GitHubTokenAuthenticator(stream=mock_stream) token_managers = auth.prepare_tokens() @@ -370,9 +408,12 @@ def test_config_app_keys(self, mock_stream): def generate_token_mock(app_id, private_key, installation_id): return (f"installationtokenfor{app_id}", MagicMock()) - with patch.object(TokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - side_effect=generate_token_mock, + with ( + patch.object(TokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + side_effect=generate_token_mock, + ), ): stream = mock_stream stream.config.update( @@ -404,13 +445,20 @@ def generate_token_mock(app_id, private_key, installation_id): } def test_env_app_key_only(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"GITHUB_APP_PRIVATE_KEY": "123;;key", "OTHER_TOKEN": "blah"}, - ), patch.object(AppTokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_APP_PRIVATE_KEY": "123;;key", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(AppTokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): auth = GitHubTokenAuthenticator(stream=mock_stream) token_managers = auth.prepare_tokens() @@ -422,18 +470,22 @@ def test_all_token_types(self, mock_stream): # Expectations: # - the presence of additional_auth_tokens causes personal tokens in the environment to be ignored. # noqa: E501 # - the other types all coexist - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={ - "GITHUB_TOKEN1": "gt1", - "GITHUB_TOKENxyz": "gt2", - "GITHUB_APP_PRIVATE_KEY": "123;;key;;install_id", - "OTHER_TOKEN": "blah", - }, - ), patch.object(TokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_TOKENxyz": "gt2", + "GITHUB_APP_PRIVATE_KEY": "123;;key;;install_id", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(TokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): stream = mock_stream stream.config.update( @@ -457,18 +509,22 @@ def test_all_token_types(self, mock_stream): def test_all_token_types_except_additional_auth_tokens(self, mock_stream): # Expectations: # - in the absence of additional_auth_tokens, all the other types can coexist - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={ - "GITHUB_TOKEN1": "gt1", - "GITHUB_TOKENxyz": "gt2", - "GITHUB_APP_PRIVATE_KEY": "123;;key;;install_id", - "OTHER_TOKEN": "blah", - }, - ), patch.object(TokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_TOKENxyz": "gt2", + "GITHUB_APP_PRIVATE_KEY": "123;;key;;install_id", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(TokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): stream = mock_stream stream.config.update( @@ -488,17 +544,21 @@ def test_all_token_types_except_additional_auth_tokens(self, mock_stream): ] def test_auth_token_and_additional_auth_tokens_deduped(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={ - "GITHUB_TOKEN1": "gt1", - "GITHUB_TOKENxyz": "gt2", - "OTHER_TOKEN": "blah", - }, - ), patch.object(TokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_TOKENxyz": "gt2", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(TokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): stream = mock_stream stream.config.update( @@ -514,18 +574,22 @@ def test_auth_token_and_additional_auth_tokens_deduped(self, mock_stream): assert sorted({tm.token for tm in token_managers}) == ["gt1", "gt8", "gt9"] def test_auth_token_and_env_tokens_deduped(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={ - "GITHUB_TOKEN1": "gt1", - "GITHUB_TOKENa": "gt2", - "GITHUB_TOKENxyz": "gt2", - "OTHER_TOKEN": "blah", - }, - ), patch.object(TokenManager, "is_valid_token", return_value=True), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_TOKENa": "gt2", + "GITHUB_TOKENxyz": "gt2", + "OTHER_TOKEN": "blah", + }, + ), + patch.object(TokenManager, "is_valid_token", return_value=True), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): stream = mock_stream stream.config.update({"auth_token": "gt1"}) @@ -540,11 +604,14 @@ def test_handle_error_if_app_key_invalid(self, mock_stream): # - don"t crash # - print the error as a warning # - continue with any other obtained tokens - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"GITHUB_APP_PRIVATE_KEY": "123garbagekey"}, - ), patch("tap_github.authenticator.AppTokenManager") as mock_app_manager: + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={"GITHUB_APP_PRIVATE_KEY": "123garbagekey"}, + ), + patch("tap_github.authenticator.AppTokenManager") as mock_app_manager, + ): mock_app_manager.side_effect = ValueError("Invalid key format") auth = GitHubTokenAuthenticator(stream=mock_stream) @@ -555,13 +622,17 @@ def test_handle_error_if_app_key_invalid(self, mock_stream): ) def test_exclude_generated_app_token_if_invalid(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"GITHUB_APP_PRIVATE_KEY": "123;;key"}, - ), patch.object(AppTokenManager, "is_valid_token", return_value=False), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={"GITHUB_APP_PRIVATE_KEY": "123;;key"}, + ), + patch.object(AppTokenManager, "is_valid_token", return_value=False), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): auth = GitHubTokenAuthenticator(stream=mock_stream) token_managers = auth.prepare_tokens() @@ -569,15 +640,21 @@ def test_exclude_generated_app_token_if_invalid(self, mock_stream): assert len(token_managers) == 0 def test_prepare_tokens_returns_empty_if_all_tokens_invalid(self, mock_stream): - with patch.object( - GitHubTokenAuthenticator, - "get_env", - return_value={"GITHUB_TOKEN1": "gt1", "GITHUB_APP_PRIVATE_KEY": "123;;key"}, - ), patch.object( - PersonalTokenManager, "is_valid_token", return_value=False - ), patch.object(AppTokenManager, "is_valid_token", return_value=False), patch( - "tap_github.authenticator.generate_app_access_token", - return_value=("installationtoken12345", MagicMock()), + with ( + patch.object( + GitHubTokenAuthenticator, + "get_env", + return_value={ + "GITHUB_TOKEN1": "gt1", + "GITHUB_APP_PRIVATE_KEY": "123;;key", + }, + ), + patch.object(PersonalTokenManager, "is_valid_token", return_value=False), + patch.object(AppTokenManager, "is_valid_token", return_value=False), + patch( + "tap_github.authenticator.generate_app_access_token", + return_value=("installationtoken12345", MagicMock()), + ), ): stream = mock_stream stream.config.update( diff --git a/tap_github/tests/test_core.py b/tap_github/tests/test_core.py index 891eaf18..90c5b9b7 100644 --- a/tap_github/tests/test_core.py +++ b/tap_github/tests/test_core.py @@ -23,9 +23,12 @@ def test_standard_tap_tests_for_search_mode(search_config): # noqa: F811 """Run standard tap tests from the SDK.""" tests = get_standard_tap_tests(TapGitHub, config=search_config) - with patch( - "singer_sdk.streams.core.Stream._sync_children", alternative_sync_chidren - ), nostdout(): + with ( + patch( + "singer_sdk.streams.core.Stream._sync_children", alternative_sync_chidren + ), + nostdout(), + ): for test in tests: test() @@ -33,9 +36,12 @@ def test_standard_tap_tests_for_search_mode(search_config): # noqa: F811 def test_standard_tap_tests_for_repo_list_mode(repo_list_config): # noqa: F811 """Run standard tap tests from the SDK.""" tests = get_standard_tap_tests(TapGitHub, config=repo_list_config) - with patch( - "singer_sdk.streams.core.Stream._sync_children", alternative_sync_chidren - ), nostdout(): + with ( + patch( + "singer_sdk.streams.core.Stream._sync_children", alternative_sync_chidren + ), + nostdout(), + ): for test in tests: test() diff --git a/tap_github/user_streams.py b/tap_github/user_streams.py index 5836fa0b..14df91b3 100644 --- a/tap_github/user_streams.py +++ b/tap_github/user_streams.py @@ -3,7 +3,7 @@ from __future__ import annotations import re -from typing import Any, ClassVar, Iterable +from typing import TYPE_CHECKING, Any, ClassVar from singer_sdk import typing as th # JSON Schema typing helpers from singer_sdk.exceptions import FatalAPIError @@ -11,6 +11,9 @@ from tap_github.client import GitHubGraphqlStream, GitHubRestStream from tap_github.schema_objects import user_object +if TYPE_CHECKING: + from collections.abc import Iterable + class UserStream(GitHubRestStream): """Defines 'User' stream.""" diff --git a/tap_github/utils/filter_stdout.py b/tap_github/utils/filter_stdout.py index 72441413..e4fd6a66 100644 --- a/tap_github/utils/filter_stdout.py +++ b/tap_github/utils/filter_stdout.py @@ -4,7 +4,8 @@ import io import re import sys -from typing import Pattern, TextIO +from re import Pattern +from typing import TextIO class FilterStdOutput: