diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..28b94c1 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,57 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-ast + - id: check-case-conflict + - id: trailing-whitespace + - id: end-of-file-fixer + files: ".+\\.py" + - id: debug-statements + - id: trailing-whitespace + - id: detect-aws-credentials + args: [--allow-missing-credentials] + - id: check-docstring-first + - id: check-merge-conflict + - id: check-symlinks + - id: check-toml + - id: detect-private-key + - id: requirements-txt-fixer + + - repo: https://github.com/psf/black + rev: 23.9.1 # Replace by any tag/version: https://github.com/psf/black/tags + hooks: + - id: black + language_version: python3 # Should be a command that runs python3.6+ + + - repo: https://github.com/pycqa/isort + rev: 5.12.0 + hooks: + - id: isort + args: ["--profile", "black"] + + - repo: https://github.com/pycqa/pylint + rev: v3.0.0a7 + hooks: + - id: pylint + + - repo: local + hooks: + - id: prospector + name: Python quality check + entry: prospector + language: python + types: [ python ] + exclude: ".*/tests/.*" + + - repo: https://github.com/charliermarsh/ruff-pre-commit + # Ruff version. + rev: 'v0.0.291' + hooks: + - id: ruff + args: [--exit-non-zero-on-fix] # don't use --fix as it corrupts the files + + - repo: https://github.com/kynan/nbstripout + rev: 0.6.1 + hooks: + - id: nbstripout \ No newline at end of file diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..48b7c84 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,2004 @@ +# This file is automatically @generated by Poetry 1.6.1 and should not be changed by hand. + +[[package]] +name = "argcomplete" +version = "2.0.6" +description = "Bash tab completion for argparse" +optional = false +python-versions = ">=3.6" +files = [ + {file = "argcomplete-2.0.6-py3-none-any.whl", hash = "sha256:6c2170b3e0ab54683cb28d319b65261bde1f11388be688b68118b7d281e34c94"}, + {file = "argcomplete-2.0.6.tar.gz", hash = "sha256:dc33528d96727882b576b24bc89ed038f3c6abbb6855ff9bb6be23384afff9d6"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=0.23,<6", markers = "python_version == \"3.7\""} + +[package.extras] +lint = ["flake8", "mypy"] +test = ["coverage", "flake8", "mypy", "pexpect", "wheel"] + +[[package]] +name = "astroid" +version = "2.15.7" +description = "An abstract syntax tree for Python with inference support." +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "astroid-2.15.7-py3-none-any.whl", hash = "sha256:958f280532e36ca84a13023f15cb1556fb6792d193acb87e1f3ca536b6fa6bd2"}, + {file = "astroid-2.15.7.tar.gz", hash = "sha256:c522f2832a900e27a7d284b9b6ef670d2495f760ede3c8c0b004a5641d3c5987"}, +] + +[package.dependencies] +lazy-object-proxy = ">=1.4.0" +typed-ast = {version = ">=1.4.0,<2.0", markers = "implementation_name == \"cpython\" and python_version < \"3.8\""} +typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} +wrapt = [ + {version = ">=1.11,<2", markers = "python_version < \"3.11\""}, + {version = ">=1.14,<2", markers = "python_version >= \"3.11\""}, +] + +[[package]] +name = "black" +version = "23.3.0" +description = "The uncompromising code formatter." +optional = false +python-versions = ">=3.7" +files = [ + {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, + {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, + {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, + {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, + {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, + {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, + {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, + {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, + {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, + {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, + {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, + {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, + {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, + {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, +] + +[package.dependencies] +click = ">=8.0.0" +mypy-extensions = ">=0.4.3" +packaging = ">=22.0" +pathspec = ">=0.9.0" +platformdirs = ">=2" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} +typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.7.4)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "bleach" +version = "6.0.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.7" +files = [ + {file = "bleach-6.0.0-py3-none-any.whl", hash = "sha256:33c16e3353dbd13028ab4799a0f89a83f113405c766e9c122df8a06f5b85b3f4"}, + {file = "bleach-6.0.0.tar.gz", hash = "sha256:1a1a85c1595e07d8db14c5f09f09e6433502c51c595970edc090551f0db99414"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.2)"] + +[[package]] +name = "certifi" +version = "2023.7.22" +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"}, +] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "cfgv" +version = "3.3.1" +description = "Validate configuration and produce human readable error messages." +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "cfgv-3.3.1-py2.py3-none-any.whl", hash = "sha256:c6a0883f3917a037485059700b9e75da2464e6c27051014ad85ba6aaa5884426"}, + {file = "cfgv-3.3.1.tar.gz", hash = "sha256:f5a830efb9ce7a445376bb66ec94c638a9787422f96264c98edc6bdeed8ab736"}, +] + +[[package]] +name = "charset-normalizer" +version = "2.1.1" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"}, + {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"}, +] + +[package.extras] +unicode-backport = ["unicodedata2"] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "commitizen" +version = "2.42.1" +description = "Python commitizen client tool" +optional = false +python-versions = ">=3.6.2,<4.0.0" +files = [ + {file = "commitizen-2.42.1-py3-none-any.whl", hash = "sha256:fad7d37cfae361a859b713d4ac591859d5ca03137dd52de4e1bd208f7f45d5dc"}, + {file = "commitizen-2.42.1.tar.gz", hash = "sha256:eac18c7c65587061aac6829534907aeb208405b8230bfd35ec08503c228a7f17"}, +] + +[package.dependencies] +argcomplete = ">=1.12.1,<2.1" +charset-normalizer = ">=2.1.0,<3.0.0" +colorama = ">=0.4.1,<0.5.0" +decli = ">=0.5.2,<0.6.0" +jinja2 = ">=2.10.3" +packaging = ">=19" +pyyaml = ">=3.08" +questionary = ">=1.4.0,<2.0.0" +termcolor = {version = ">=1.1,<3", markers = "python_version >= \"3.7\""} +tomlkit = ">=0.5.3,<1.0.0" +typing-extensions = ">=4.0.1,<5.0.0" + +[[package]] +name = "coverage" +version = "7.2.7" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, + {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, + {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, + {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, + {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, + {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, + {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, + {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, + {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, + {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, + {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, + {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, + {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, + {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, + {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, + {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, + {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, + {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, + {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, + {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, + {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, + {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, + {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, + {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, + {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, + {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, + {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, + {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, + {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, + {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, + {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, + {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, + {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "cryptography" +version = "41.0.4" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:80907d3faa55dc5434a16579952ac6da800935cd98d14dbd62f6f042c7f5e839"}, + {file = "cryptography-41.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:35c00f637cd0b9d5b6c6bd11b6c3359194a8eba9c46d4e875a3660e3b400005f"}, + {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cecfefa17042941f94ab54f769c8ce0fe14beff2694e9ac684176a2535bf9714"}, + {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e40211b4923ba5a6dc9769eab704bdb3fbb58d56c5b336d30996c24fcf12aadb"}, + {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:23a25c09dfd0d9f28da2352503b23e086f8e78096b9fd585d1d14eca01613e13"}, + {file = "cryptography-41.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:2ed09183922d66c4ec5fdaa59b4d14e105c084dd0febd27452de8f6f74704143"}, + {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:5a0f09cefded00e648a127048119f77bc2b2ec61e736660b5789e638f43cc397"}, + {file = "cryptography-41.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:9eeb77214afae972a00dee47382d2591abe77bdae166bda672fb1e24702a3860"}, + {file = "cryptography-41.0.4-cp37-abi3-win32.whl", hash = "sha256:3b224890962a2d7b57cf5eeb16ccaafba6083f7b811829f00476309bce2fe0fd"}, + {file = "cryptography-41.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c880eba5175f4307129784eca96f4e70b88e57aa3f680aeba3bab0e980b0f37d"}, + {file = "cryptography-41.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:004b6ccc95943f6a9ad3142cfabcc769d7ee38a3f60fb0dddbfb431f818c3a67"}, + {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:86defa8d248c3fa029da68ce61fe735432b047e32179883bdb1e79ed9bb8195e"}, + {file = "cryptography-41.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:37480760ae08065437e6573d14be973112c9e6dcaf5f11d00147ee74f37a3829"}, + {file = "cryptography-41.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b5f4dfe950ff0479f1f00eda09c18798d4f49b98f4e2006d644b3301682ebdca"}, + {file = "cryptography-41.0.4-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7e53db173370dea832190870e975a1e09c86a879b613948f09eb49324218c14d"}, + {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:5b72205a360f3b6176485a333256b9bcd48700fc755fef51c8e7e67c4b63e3ac"}, + {file = "cryptography-41.0.4-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:93530900d14c37a46ce3d6c9e6fd35dbe5f5601bf6b3a5c325c7bffc030344d9"}, + {file = "cryptography-41.0.4-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:efc8ad4e6fc4f1752ebfb58aefece8b4e3c4cae940b0994d43649bdfce8d0d4f"}, + {file = "cryptography-41.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c3391bd8e6de35f6f1140e50aaeb3e2b3d6a9012536ca23ab0d9c35ec18c8a91"}, + {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0d9409894f495d465fe6fda92cb70e8323e9648af912d5b9141d616df40a87b8"}, + {file = "cryptography-41.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:8ac4f9ead4bbd0bc8ab2d318f97d85147167a488be0e08814a37eb2f439d5cf6"}, + {file = "cryptography-41.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:047c4603aeb4bbd8db2756e38f5b8bd7e94318c047cfe4efeb5d715e08b49311"}, + {file = "cryptography-41.0.4.tar.gz", hash = "sha256:7febc3094125fc126a7f6fb1f420d0da639f3f32cb15c8ff0dc3997c4549f51a"}, +] + +[package.dependencies] +cffi = ">=1.12" + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +nox = ["nox"] +pep8test = ["black", "check-sdist", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "decli" +version = "0.5.2" +description = "Minimal, easy-to-use, declarative cli tool" +optional = false +python-versions = ">=3.6" +files = [ + {file = "decli-0.5.2-py3-none-any.whl", hash = "sha256:d3207bc02d0169bf6ed74ccca09ce62edca0eb25b0ebf8bf4ae3fb8333e15ca0"}, + {file = "decli-0.5.2.tar.gz", hash = "sha256:f2cde55034a75c819c630c7655a844c612f2598c42c21299160465df6ad463ad"}, +] + +[[package]] +name = "dill" +version = "0.3.7" +description = "serialize all of Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "dill-0.3.7-py3-none-any.whl", hash = "sha256:76b122c08ef4ce2eedcd4d1abd8e641114bfc6c2867f49f3c41facf65bf19f5e"}, + {file = "dill-0.3.7.tar.gz", hash = "sha256:cc1c8b182eb3013e24bd475ff2e9295af86c1a38eb1aff128dac8962a9ce3c03"}, +] + +[package.extras] +graph = ["objgraph (>=1.7.2)"] + +[[package]] +name = "distlib" +version = "0.3.7" +description = "Distribution utilities" +optional = false +python-versions = "*" +files = [ + {file = "distlib-0.3.7-py2.py3-none-any.whl", hash = "sha256:2e24928bc811348f0feb63014e97aaae3037f2cf48712d51ae61df7fd6075057"}, + {file = "distlib-0.3.7.tar.gz", hash = "sha256:9dafe54b34a028eafd95039d5e5d4851a13734540f1331060d31c9916e7147a8"}, +] + +[[package]] +name = "dnspython" +version = "2.3.0" +description = "DNS toolkit" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "dnspython-2.3.0-py3-none-any.whl", hash = "sha256:89141536394f909066cabd112e3e1a37e4e654db00a25308b0f130bc3152eb46"}, + {file = "dnspython-2.3.0.tar.gz", hash = "sha256:224e32b03eb46be70e12ef6d64e0be123a64e621ab4c0822ff6d450d52a540b9"}, +] + +[package.extras] +curio = ["curio (>=1.2,<2.0)", "sniffio (>=1.1,<2.0)"] +dnssec = ["cryptography (>=2.6,<40.0)"] +doh = ["h2 (>=4.1.0)", "httpx (>=0.21.1)", "requests (>=2.23.0,<3.0.0)", "requests-toolbelt (>=0.9.1,<0.11.0)"] +doq = ["aioquic (>=0.9.20)"] +idna = ["idna (>=2.1,<4.0)"] +trio = ["trio (>=0.14,<0.23)"] +wmi = ["wmi (>=1.5.1,<2.0.0)"] + +[[package]] +name = "docutils" +version = "0.20.1" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, + {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, +] + +[[package]] +name = "dodgy" +version = "0.2.1" +description = "Dodgy: Searches for dodgy looking lines in Python code" +optional = false +python-versions = "*" +files = [ + {file = "dodgy-0.2.1-py3-none-any.whl", hash = "sha256:51f54c0fd886fa3854387f354b19f429d38c04f984f38bc572558b703c0542a6"}, + {file = "dodgy-0.2.1.tar.gz", hash = "sha256:28323cbfc9352139fdd3d316fa17f325cc0e9ac74438cbba51d70f9b48f86c3a"}, +] + +[[package]] +name = "eventlet" +version = "0.33.3" +description = "Highly concurrent networking library" +optional = false +python-versions = "*" +files = [ + {file = "eventlet-0.33.3-py2.py3-none-any.whl", hash = "sha256:e43b9ae05ba4bb477a10307699c9aff7ff86121b2640f9184d29059f5a687df8"}, + {file = "eventlet-0.33.3.tar.gz", hash = "sha256:722803e7eadff295347539da363d68ae155b8b26ae6a634474d0a920be73cfda"}, +] + +[package.dependencies] +dnspython = ">=1.15.0" +greenlet = ">=0.3" +six = ">=1.10.0" + +[[package]] +name = "exceptiongroup" +version = "1.1.3" +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"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "filelock" +version = "3.12.2" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.7" +files = [ + {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, + {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, +] + +[package.extras] +docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "flake8" +version = "2.3.0" +description = "the modular source code checker: pep8, pyflakes and co" +optional = false +python-versions = "*" +files = [ + {file = "flake8-2.3.0-py2.py3-none-any.whl", hash = "sha256:c99cc9716d6655d9c8bcb1e77632b8615bf0abd282d7abd9f5c2148cad7fc669"}, + {file = "flake8-2.3.0.tar.gz", hash = "sha256:5ee1a43ccd0716d6061521eec6937c983efa027793013e572712c4da55c7c83e"}, +] + +[package.dependencies] +mccabe = ">=0.2.1" +pep8 = ">=1.5.7" +pyflakes = ">=0.8.1" + +[[package]] +name = "flake8-polyfill" +version = "1.0.2" +description = "Polyfill package for Flake8 plugins" +optional = false +python-versions = "*" +files = [ + {file = "flake8-polyfill-1.0.2.tar.gz", hash = "sha256:e44b087597f6da52ec6393a709e7108b2905317d0c0b744cdca6208e670d8eda"}, + {file = "flake8_polyfill-1.0.2-py2.py3-none-any.whl", hash = "sha256:12be6a34ee3ab795b19ca73505e7b55826d5f6ad7230d31b18e106400169b9e9"}, +] + +[package.dependencies] +flake8 = "*" + +[[package]] +name = "gitdb" +version = "4.0.10" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, + {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.37" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.37-py3-none-any.whl", hash = "sha256:5f4c4187de49616d710a77e98ddf17b4782060a1788df441846bddefbb89ab33"}, + {file = "GitPython-3.1.37.tar.gz", hash = "sha256:f9b9ddc0761c125d5780eab2d64be4873fc6817c2899cbcb34b02344bdc7bc54"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" +typing-extensions = {version = ">=3.7.4.3", markers = "python_version < \"3.8\""} + +[package.extras] +test = ["black", "coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mypy", "pre-commit", "pytest", "pytest-cov", "pytest-sugar"] + +[[package]] +name = "greenlet" +version = "2.0.2" +description = "Lightweight in-process concurrent programming" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*" +files = [ + {file = "greenlet-2.0.2-cp27-cp27m-macosx_10_14_x86_64.whl", hash = "sha256:bdfea8c661e80d3c1c99ad7c3ff74e6e87184895bbaca6ee8cc61209f8b9b85d"}, + {file = "greenlet-2.0.2-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:9d14b83fab60d5e8abe587d51c75b252bcc21683f24699ada8fb275d7712f5a9"}, + {file = "greenlet-2.0.2-cp27-cp27m-win32.whl", hash = "sha256:6c3acb79b0bfd4fe733dff8bc62695283b57949ebcca05ae5c129eb606ff2d74"}, + {file = "greenlet-2.0.2-cp27-cp27m-win_amd64.whl", hash = "sha256:283737e0da3f08bd637b5ad058507e578dd462db259f7f6e4c5c365ba4ee9343"}, + {file = "greenlet-2.0.2-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:d27ec7509b9c18b6d73f2f5ede2622441de812e7b1a80bbd446cb0633bd3d5ae"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d967650d3f56af314b72df7089d96cda1083a7fc2da05b375d2bc48c82ab3f3c"}, + {file = "greenlet-2.0.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:30bcf80dda7f15ac77ba5af2b961bdd9dbc77fd4ac6105cee85b0d0a5fcf74df"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26fbfce90728d82bc9e6c38ea4d038cba20b7faf8a0ca53a9c07b67318d46088"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9190f09060ea4debddd24665d6804b995a9c122ef5917ab26e1566dcc712ceeb"}, + {file = "greenlet-2.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d75209eed723105f9596807495d58d10b3470fa6732dd6756595e89925ce2470"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3a51c9751078733d88e013587b108f1b7a1fb106d402fb390740f002b6f6551a"}, + {file = "greenlet-2.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:76ae285c8104046b3a7f06b42f29c7b73f77683df18c49ab5af7983994c2dd91"}, + {file = "greenlet-2.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:2d4686f195e32d36b4d7cf2d166857dbd0ee9f3d20ae349b6bf8afc8485b3645"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c4302695ad8027363e96311df24ee28978162cdcdd2006476c43970b384a244c"}, + {file = "greenlet-2.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d4606a527e30548153be1a9f155f4e283d109ffba663a15856089fb55f933e47"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c48f54ef8e05f04d6eff74b8233f6063cb1ed960243eacc474ee73a2ea8573ca"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a1846f1b999e78e13837c93c778dcfc3365902cfb8d1bdb7dd73ead37059f0d0"}, + {file = "greenlet-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a06ad5312349fec0ab944664b01d26f8d1f05009566339ac6f63f56589bc1a2"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:eff4eb9b7eb3e4d0cae3d28c283dc16d9bed6b193c2e1ace3ed86ce48ea8df19"}, + {file = "greenlet-2.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:5454276c07d27a740c5892f4907c86327b632127dd9abec42ee62e12427ff7e3"}, + {file = "greenlet-2.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:7cafd1208fdbe93b67c7086876f061f660cfddc44f404279c1585bbf3cdc64c5"}, + {file = "greenlet-2.0.2-cp35-cp35m-macosx_10_14_x86_64.whl", hash = "sha256:910841381caba4f744a44bf81bfd573c94e10b3045ee00de0cbf436fe50673a6"}, + {file = "greenlet-2.0.2-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:18a7f18b82b52ee85322d7a7874e676f34ab319b9f8cce5de06067384aa8ff43"}, + {file = "greenlet-2.0.2-cp35-cp35m-win32.whl", hash = "sha256:03a8f4f3430c3b3ff8d10a2a86028c660355ab637cee9333d63d66b56f09d52a"}, + {file = "greenlet-2.0.2-cp35-cp35m-win_amd64.whl", hash = "sha256:4b58adb399c4d61d912c4c331984d60eb66565175cdf4a34792cd9600f21b394"}, + {file = "greenlet-2.0.2-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:703f18f3fda276b9a916f0934d2fb6d989bf0b4fb5a64825260eb9bfd52d78f0"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:32e5b64b148966d9cccc2c8d35a671409e45f195864560829f395a54226408d3"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dd11f291565a81d71dab10b7033395b7a3a5456e637cf997a6f33ebdf06f8db"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e0f72c9ddb8cd28532185f54cc1453f2c16fb417a08b53a855c4e6a418edd099"}, + {file = "greenlet-2.0.2-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cd021c754b162c0fb55ad5d6b9d960db667faad0fa2ff25bb6e1301b0b6e6a75"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:3c9b12575734155d0c09d6c3e10dbd81665d5c18e1a7c6597df72fd05990c8cf"}, + {file = "greenlet-2.0.2-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b9ec052b06a0524f0e35bd8790686a1da006bd911dd1ef7d50b77bfbad74e292"}, + {file = "greenlet-2.0.2-cp36-cp36m-win32.whl", hash = "sha256:dbfcfc0218093a19c252ca8eb9aee3d29cfdcb586df21049b9d777fd32c14fd9"}, + {file = "greenlet-2.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:9f35ec95538f50292f6d8f2c9c9f8a3c6540bbfec21c9e5b4b751e0a7c20864f"}, + {file = "greenlet-2.0.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:d5508f0b173e6aa47273bdc0a0b5ba055b59662ba7c7ee5119528f466585526b"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:f82d4d717d8ef19188687aa32b8363e96062911e63ba22a0cff7802a8e58e5f1"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9c59a2120b55788e800d82dfa99b9e156ff8f2227f07c5e3012a45a399620b7"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2780572ec463d44c1d3ae850239508dbeb9fed38e294c68d19a24d925d9223ca"}, + {file = "greenlet-2.0.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:937e9020b514ceedb9c830c55d5c9872abc90f4b5862f89c0887033ae33c6f73"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:36abbf031e1c0f79dd5d596bfaf8e921c41df2bdf54ee1eed921ce1f52999a86"}, + {file = "greenlet-2.0.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:18e98fb3de7dba1c0a852731c3070cf022d14f0d68b4c87a19cc1016f3bb8b33"}, + {file = "greenlet-2.0.2-cp37-cp37m-win32.whl", hash = "sha256:3f6ea9bd35eb450837a3d80e77b517ea5bc56b4647f5502cd28de13675ee12f7"}, + {file = "greenlet-2.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:7492e2b7bd7c9b9916388d9df23fa49d9b88ac0640db0a5b4ecc2b653bf451e3"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:b864ba53912b6c3ab6bcb2beb19f19edd01a6bfcbdfe1f37ddd1778abfe75a30"}, + {file = "greenlet-2.0.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:1087300cf9700bbf455b1b97e24db18f2f77b55302a68272c56209d5587c12d1"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:ba2956617f1c42598a308a84c6cf021a90ff3862eddafd20c3333d50f0edb45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc3a569657468b6f3fb60587e48356fe512c1754ca05a564f11366ac9e306526"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8eab883b3b2a38cc1e050819ef06a7e6344d4a990d24d45bc6f2cf959045a45b"}, + {file = "greenlet-2.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acd2162a36d3de67ee896c43effcd5ee3de247eb00354db411feb025aa319857"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0bf60faf0bc2468089bdc5edd10555bab6e85152191df713e2ab1fcc86382b5a"}, + {file = "greenlet-2.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b0ef99cdbe2b682b9ccbb964743a6aca37905fda5e0452e5ee239b1654d37f2a"}, + {file = "greenlet-2.0.2-cp38-cp38-win32.whl", hash = "sha256:b80f600eddddce72320dbbc8e3784d16bd3fb7b517e82476d8da921f27d4b249"}, + {file = "greenlet-2.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:4d2e11331fc0c02b6e84b0d28ece3a36e0548ee1a1ce9ddde03752d9b79bba40"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8512a0c38cfd4e66a858ddd1b17705587900dd760c6003998e9472b77b56d417"}, + {file = "greenlet-2.0.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:88d9ab96491d38a5ab7c56dd7a3cc37d83336ecc564e4e8816dbed12e5aaefc8"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:561091a7be172ab497a3527602d467e2b3fbe75f9e783d8b8ce403fa414f71a6"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:971ce5e14dc5e73715755d0ca2975ac88cfdaefcaab078a284fea6cfabf866df"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:be4ed120b52ae4d974aa40215fcdfde9194d63541c7ded40ee12eb4dda57b76b"}, + {file = "greenlet-2.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94c817e84245513926588caf1152e3b559ff794d505555211ca041f032abbb6b"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1a819eef4b0e0b96bb0d98d797bef17dc1b4a10e8d7446be32d1da33e095dbb8"}, + {file = "greenlet-2.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7efde645ca1cc441d6dc4b48c0f7101e8d86b54c8530141b09fd31cef5149ec9"}, + {file = "greenlet-2.0.2-cp39-cp39-win32.whl", hash = "sha256:ea9872c80c132f4663822dd2a08d404073a5a9b5ba6155bea72fb2a79d1093b5"}, + {file = "greenlet-2.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:db1a39669102a1d8d12b57de2bb7e2ec9066a6f2b3da35ae511ff93b01b5d564"}, + {file = "greenlet-2.0.2.tar.gz", hash = "sha256:e7c8dc13af7db097bed64a051d2dd49e9f0af495c26995c00a9ee842690d34c0"}, +] + +[package.extras] +docs = ["Sphinx", "docutils (<0.18)"] +test = ["objgraph", "psutil"] + +[[package]] +name = "identify" +version = "2.5.24" +description = "File identification library for Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, +] + +[package.extras] +license = ["ukkonen"] + +[[package]] +name = "idna" +version = "3.4" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"}, + {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"}, +] + +[[package]] +name = "importlib-metadata" +version = "4.13.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-4.13.0-py3-none-any.whl", hash = "sha256:8a8a81bcf996e74fee46f0d16bd3eaa382a7eb20fd82445c3ad11f4090334116"}, + {file = "importlib_metadata-4.13.0.tar.gz", hash = "sha256:dd0173e8f150d6815e098fd354f6414b0f079af4644ddfe90c71e2fc6174346d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +perf = ["ipython"] +testing = ["flake8 (<5)", "flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"] + +[[package]] +name = "importlib-resources" +version = "5.12.0" +description = "Read resources from Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_resources-5.12.0-py3-none-any.whl", hash = "sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a"}, + {file = "importlib_resources-5.12.0.tar.gz", hash = "sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6"}, +] + +[package.dependencies] +zipp = {version = ">=3.1.0", markers = "python_version < \"3.10\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "invoke" +version = "2.0.1" +description = "Pythonic task execution" +optional = false +python-versions = ">=3.6" +files = [ + {file = "invoke-2.0.1-py3-none-any.whl", hash = "sha256:037393e21de251078b2a59f539dc63b7cc7bb778787aa56f6dc4d86d3b29abec"}, + {file = "invoke-2.0.1.tar.gz", hash = "sha256:6e4da849cb9d1d007fbfbaf3f44d2f4a5ad9ecf95073a3b834d38a8ac99cf860"}, +] + +[[package]] +name = "isort" +version = "5.11.5" +description = "A Python utility / library to sort Python imports." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "isort-5.11.5-py3-none-any.whl", hash = "sha256:ba1d72fb2595a01c7895a5128f9585a5cc4b6d395f1c8d514989b9a7eb2a8746"}, + {file = "isort-5.11.5.tar.gz", hash = "sha256:6be1f76a507cb2ecf16c7cf14a37e41609ca082330be4e3436a18ef74add55db"}, +] + +[package.extras] +colors = ["colorama (>=0.4.3,<0.5.0)"] +pipfile-deprecated-finder = ["pip-shims (>=0.5.2)", "pipreqs", "requirementslib"] +plugins = ["setuptools"] +requirements-deprecated-finder = ["pip-api", "pipreqs"] + +[[package]] +name = "jaraco-classes" +version = "3.2.3" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jaraco.classes-3.2.3-py3-none-any.whl", hash = "sha256:2353de3288bc6b82120752201c6b1c1a14b058267fa424ed5ce5984e3b922158"}, + {file = "jaraco.classes-3.2.3.tar.gz", hash = "sha256:89559fa5c1d3c34eff6f631ad80bb21f378dbcbb35dd161fd2c6b93f5be2f98a"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)"] +testing = ["flake8 (<5)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[[package]] +name = "jeepney" +version = "0.8.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jeepney-0.8.0-py3-none-any.whl", hash = "sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755"}, + {file = "jeepney-0.8.0.tar.gz", hash = "sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806"}, +] + +[package.extras] +test = ["async-timeout", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["async_generator", "trio"] + +[[package]] +name = "jinja2" +version = "3.1.2" +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"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "keyring" +version = "24.1.1" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.7" +files = [ + {file = "keyring-24.1.1-py3-none-any.whl", hash = "sha256:bc402c5e501053098bcbd149c4ddbf8e36c6809e572c2d098d4961e88d4c270d"}, + {file = "keyring-24.1.1.tar.gz", hash = "sha256:3d44a48fa9a254f6c72879d7c88604831ebdaac6ecb0b214308b02953502c510"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +importlib-resources = {version = "*", markers = "python_version < \"3.9\""} +"jaraco.classes" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +completion = ["shtab"] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-ruff"] + +[[package]] +name = "lazy-object-proxy" +version = "1.9.0" +description = "A fast and thorough lazy object proxy." +optional = false +python-versions = ">=3.7" +files = [ + {file = "lazy-object-proxy-1.9.0.tar.gz", hash = "sha256:659fb5809fa4629b8a1ac5106f669cfc7bef26fbb389dda53b3e010d1ac4ebae"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b40387277b0ed2d0602b8293b94d7257e17d1479e257b4de114ea11a8cb7f2d7"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8c6cfb338b133fbdbc5cfaa10fe3c6aeea827db80c978dbd13bc9dd8526b7d4"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:721532711daa7db0d8b779b0bb0318fa87af1c10d7fe5e52ef30f8eff254d0cd"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:66a3de4a3ec06cd8af3f61b8e1ec67614fbb7c995d02fa224813cb7afefee701"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:1aa3de4088c89a1b69f8ec0dcc169aa725b0ff017899ac568fe44ddc1396df46"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win32.whl", hash = "sha256:f0705c376533ed2a9e5e97aacdbfe04cecd71e0aa84c7c0595d02ef93b6e4455"}, + {file = "lazy_object_proxy-1.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea806fd4c37bf7e7ad82537b0757999264d5f70c45468447bb2b91afdbe73a6e"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:946d27deaff6cf8452ed0dba83ba38839a87f4f7a9732e8f9fd4107b21e6ff07"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79a31b086e7e68b24b99b23d57723ef7e2c6d81ed21007b6281ebcd1688acb0a"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f699ac1c768270c9e384e4cbd268d6e67aebcfae6cd623b4d7c3bfde5a35db59"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfb38f9ffb53b942f2b5954e0f610f1e721ccebe9cce9025a38c8ccf4a5183a4"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:189bbd5d41ae7a498397287c408617fe5c48633e7755287b21d741f7db2706a9"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win32.whl", hash = "sha256:81fc4d08b062b535d95c9ea70dbe8a335c45c04029878e62d744bdced5141586"}, + {file = "lazy_object_proxy-1.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:f2457189d8257dd41ae9b434ba33298aec198e30adf2dcdaaa3a28b9994f6adb"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:d9e25ef10a39e8afe59a5c348a4dbf29b4868ab76269f81ce1674494e2565a6e"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cbf9b082426036e19c6924a9ce90c740a9861e2bdc27a4834fd0a910742ac1e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f5fa4a61ce2438267163891961cfd5e32ec97a2c444e5b842d574251ade27d2"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8fa02eaab317b1e9e03f69aab1f91e120e7899b392c4fc19807a8278a07a97e8"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:e7c21c95cae3c05c14aafffe2865bbd5e377cfc1348c4f7751d9dc9a48ca4bda"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win32.whl", hash = "sha256:f12ad7126ae0c98d601a7ee504c1122bcef553d1d5e0c3bfa77b16b3968d2734"}, + {file = "lazy_object_proxy-1.9.0-cp37-cp37m-win_amd64.whl", hash = "sha256:edd20c5a55acb67c7ed471fa2b5fb66cb17f61430b7a6b9c3b4a1e40293b1671"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2d0daa332786cf3bb49e10dc6a17a52f6a8f9601b4cf5c295a4f85854d61de63"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cd077f3d04a58e83d04b20e334f678c2b0ff9879b9375ed107d5d07ff160171"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c94ea760b3ce47d1855a30984c78327500493d396eac4dfd8bd82041b22be"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:212774e4dfa851e74d393a2370871e174d7ff0ebc980907723bb67d25c8a7c30"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:f0117049dd1d5635bbff65444496c90e0baa48ea405125c088e93d9cf4525b11"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win32.whl", hash = "sha256:0a891e4e41b54fd5b8313b96399f8b0e173bbbfc03c7631f01efbe29bb0bcf82"}, + {file = "lazy_object_proxy-1.9.0-cp38-cp38-win_amd64.whl", hash = "sha256:9990d8e71b9f6488e91ad25f322898c136b008d87bf852ff65391b004da5e17b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9e7551208b2aded9c1447453ee366f1c4070602b3d932ace044715d89666899b"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f83ac4d83ef0ab017683d715ed356e30dd48a93746309c8f3517e1287523ef4"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7322c3d6f1766d4ef1e51a465f47955f1e8123caee67dd641e67d539a534d006"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:18b78ec83edbbeb69efdc0e9c1cb41a3b1b1ed11ddd8ded602464c3fc6020494"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:09763491ce220c0299688940f8dc2c5d05fd1f45af1e42e636b2e8b2303e4382"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win32.whl", hash = "sha256:9090d8e53235aa280fc9239a86ae3ea8ac58eff66a705fa6aa2ec4968b95c821"}, + {file = "lazy_object_proxy-1.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:db1c1722726f47e10e0b5fdbf15ac3b8adb58c091d12b3ab713965795036985f"}, +] + +[[package]] +name = "markdown-it-py" +version = "2.2.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.7" +files = [ + {file = "markdown-it-py-2.2.0.tar.gz", hash = "sha256:7c9a5e412688bc771c67432cbfebcdd686c93ce6484913dccf06cb5a0bea35a1"}, + {file = "markdown_it_py-2.2.0-py3-none-any.whl", hash = "sha256:5a35f8d1870171d9acc47b99612dc146129b631baf04970128b568f190d0cc30"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" +typing_extensions = {version = ">=3.7.4", markers = "python_version < \"3.8\""} + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["attrs", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.3" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +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-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8e254ae696c88d98da6555f5ace2279cf7cd5b3f52be2b5cf97feafe883b58d2"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0932dc158471523c9637e807d9bfb93e06a95cbf010f1a38b98623b929ef2b"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9402b03f1a1b4dc4c19845e5c749e3ab82d5078d16a2a4c2cd2df62d57bb0707"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ca379055a47383d02a5400cb0d110cef0a776fc644cda797db0c5696cfd7e18e"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b7ff0f54cb4ff66dd38bebd335a38e2c22c41a8ee45aa608efc890ac3e3931bc"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:c011a4149cfbcf9f03994ec2edffcb8b1dc2d2aede7ca243746df97a5d41ce48"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:56d9f2ecac662ca1611d183feb03a3fa4406469dafe241673d521dd5ae92a155"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win32.whl", hash = "sha256:8758846a7e80910096950b67071243da3e5a20ed2546e6392603c096778d48e0"}, + {file = "MarkupSafe-2.1.3-cp37-cp37m-win_amd64.whl", hash = "sha256:787003c0ddb00500e49a10f2844fac87aa6ce977b90b0feaaf9de23c22508b24"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ef12179d3a291be237280175b542c07a36e7f60718296278d8593d21ca937d4"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2c1b19b3aaacc6e57b7e25710ff571c24d6c3613a45e905b1fde04d691b98ee0"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8afafd99945ead6e075b973fefa56379c5b5c53fd8937dad92c662da5d8fd5ee"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8c41976a29d078bb235fea9b2ecd3da465df42a562910f9022f1a03107bd02be"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d080e0a5eb2529460b30190fcfcc4199bd7f827663f858a226a81bc27beaa97e"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:69c0f17e9f5a7afdf2cc9fb2d1ce6aabdb3bafb7f38017c0b77862bcec2bbad8"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:504b320cd4b7eff6f968eddf81127112db685e81f7e36e75f9f84f0df46041c3"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:42de32b22b6b804f42c5d98be4f7e5e977ecdd9ee9b660fda1a3edf03b11792d"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win32.whl", hash = "sha256:ceb01949af7121f9fc39f7d27f91be8546f3fb112c608bc4029aef0bab86a2a5"}, + {file = "MarkupSafe-2.1.3-cp38-cp38-win_amd64.whl", hash = "sha256:1b40069d487e7edb2676d3fbdb2b0829ffa2cd63a2ec26c4938b2d34391b4ecc"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8023faf4e01efadfa183e863fefde0046de576c6f14659e8782065bcece22198"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6b2b56950d93e41f33b4223ead100ea0fe11f8e6ee5f641eb753ce4b77a7042b"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9dcdfd0eaf283af041973bff14a2e143b8bd64e069f4c383416ecd79a81aab58"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:05fb21170423db021895e1ea1e1f3ab3adb85d1c2333cbc2310f2a26bc77272e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:282c2cb35b5b673bbcadb33a585408104df04f14b2d9b01d4c345a3b92861c2c"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab4a0df41e7c16a1392727727e7998a467472d0ad65f3ad5e6e765015df08636"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7ef3cb2ebbf91e330e3bb937efada0edd9003683db6b57bb108c4001f37a02ea"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:0a4e4a1aff6c7ac4cd55792abf96c915634c2b97e3cc1c7129578aa68ebd754e"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win32.whl", hash = "sha256:fec21693218efe39aa7f8599346e90c705afa52c5b31ae019b2e57e8f6542bb2"}, + {file = "MarkupSafe-2.1.3-cp39-cp39-win_amd64.whl", hash = "sha256:3fd4abcb888d15a94f32b75d8fd18ee162ca0c064f35b11134be77050296d6ba"}, + {file = "MarkupSafe-2.1.3.tar.gz", hash = "sha256:af598ed32d6ae86f1b747b82783958b1a4ab8f617b06fe68795c7f026abbdcad"}, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +description = "McCabe checker, plugin for flake8" +optional = false +python-versions = ">=3.6" +files = [ + {file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"}, + {file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"}, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "more-itertools" +version = "9.1.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.7" +files = [ + {file = "more-itertools-9.1.0.tar.gz", hash = "sha256:cabaa341ad0389ea83c17a94566a53ae4c9d07349861ecb14dc6d0345cf9ac5d"}, + {file = "more_itertools-9.1.0-py3-none-any.whl", hash = "sha256:d2bc7f02446e86a68911e58ded76d6561eea00cddfb2a91e7019bbb586c799f3"}, +] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "nodeenv" +version = "1.8.0" +description = "Node.js virtual environment builder" +optional = false +python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +files = [ + {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, + {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, +] + +[package.dependencies] +setuptools = "*" + +[[package]] +name = "packaging" +version = "23.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, +] + +[[package]] +name = "pathspec" +version = "0.11.2" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, + {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, +] + +[[package]] +name = "pep8" +version = "1.7.1" +description = "Python style guide checker" +optional = false +python-versions = "*" +files = [ + {file = "pep8-1.7.1-py2.py3-none-any.whl", hash = "sha256:b22cfae5db09833bb9bd7c8463b53e1a9c9b39f12e304a8d0bba729c501827ee"}, + {file = "pep8-1.7.1.tar.gz", hash = "sha256:fe249b52e20498e59e0b5c5256aa52ee99fc295b26ec9eaa85776ffdb9fe6374"}, +] + +[[package]] +name = "pep8-naming" +version = "0.10.0" +description = "Check PEP-8 naming conventions, plugin for flake8" +optional = false +python-versions = "*" +files = [ + {file = "pep8-naming-0.10.0.tar.gz", hash = "sha256:f3b4a5f9dd72b991bf7d8e2a341d2e1aa3a884a769b5aaac4f56825c1763bf3a"}, + {file = "pep8_naming-0.10.0-py2.py3-none-any.whl", hash = "sha256:5d9f1056cb9427ce344e98d1a7f5665710e2f20f748438e308995852cfa24164"}, +] + +[package.dependencies] +flake8-polyfill = ">=1.0.2,<2" + +[[package]] +name = "pkginfo" +version = "1.9.6" +description = "Query metadata from sdists / bdists / installed packages." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pkginfo-1.9.6-py3-none-any.whl", hash = "sha256:4b7a555a6d5a22169fcc9cf7bfd78d296b0361adad412a346c1226849af5e546"}, + {file = "pkginfo-1.9.6.tar.gz", hash = "sha256:8fd5896e8718a4372f0ea9cc9d96f6417c9b986e23a4d116dda26b62cc29d046"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov"] + +[[package]] +name = "platformdirs" +version = "3.10.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +optional = false +python-versions = ">=3.7" +files = [ + {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, + {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} + +[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)"] + +[[package]] +name = "pluggy" +version = "1.2.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, + {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pre-commit" +version = "2.21.0" +description = "A framework for managing and maintaining multi-language pre-commit hooks." +optional = false +python-versions = ">=3.7" +files = [ + {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, + {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, +] + +[package.dependencies] +cfgv = ">=2.0.0" +identify = ">=1.0.0" +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +nodeenv = ">=0.11.1" +pyyaml = ">=5.1" +virtualenv = ">=20.10.0" + +[[package]] +name = "prompt-toolkit" +version = "3.0.39" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.39-py3-none-any.whl", hash = "sha256:9dffbe1d8acf91e3de75f3b544e4842382fc06c6babe903ac9acb74dc6e08d88"}, + {file = "prompt_toolkit-3.0.39.tar.gz", hash = "sha256:04505ade687dc26dc4284b1ad19a83be2f2afe83e7a828ace0c72f3a1df72aac"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "prospector" +version = "1.10.2" +description = "Prospector is a tool to analyse Python code by aggregating the result of other tools." +optional = false +python-versions = ">=3.7.2,<4.0" +files = [ + {file = "prospector-1.10.2-py3-none-any.whl", hash = "sha256:3bfe103c28bb821cca84926ca31357fbfd32405e4bf8c34ca2e55885684557e4"}, + {file = "prospector-1.10.2.tar.gz", hash = "sha256:cc8f09e79bdd32247edddf05b666940e88ad96338a84f5717b1e8c0678337821"}, +] + +[package.dependencies] +dodgy = ">=0.2.1,<0.3.0" +flake8 = "<6.0.0" +GitPython = ">=3.1.27,<4.0.0" +mccabe = ">=0.7.0,<0.8.0" +packaging = "*" +pep8-naming = ">=0.3.3,<=0.10.0" +pycodestyle = ">=2.9.0" +pydocstyle = ">=2.0.0" +pyflakes = ">=2.2.0,<3" +pylint = ">=2.8.3" +pylint-celery = "0.3" +pylint-django = ">=2.5,<2.6" +pylint-flask = "0.6" +pylint-plugin-utils = ">=0.7,<0.8" +PyYAML = "*" +requirements-detector = ">=1.2.0" +setoptconf-tmp = ">=0.3.1,<0.4.0" +toml = ">=0.10.2,<0.11.0" + +[package.extras] +with-bandit = ["bandit (>=1.5.1)"] +with-everything = ["bandit (>=1.5.1)", "mypy (>=0.600)", "pyright (>=1.1.3)", "pyroma (>=2.4)", "vulture (>=1.5)"] +with-mypy = ["mypy (>=0.600)"] +with-pyright = ["pyright (>=1.1.3)"] +with-pyroma = ["pyroma (>=2.4)"] +with-vulture = ["vulture (>=1.5)"] + +[[package]] +name = "pycodestyle" +version = "2.10.0" +description = "Python style guide checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pycodestyle-2.10.0-py2.py3-none-any.whl", hash = "sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"}, + {file = "pycodestyle-2.10.0.tar.gz", hash = "sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053"}, +] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pydocstyle" +version = "6.3.0" +description = "Python docstring style checker" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pydocstyle-6.3.0-py3-none-any.whl", hash = "sha256:118762d452a49d6b05e194ef344a55822987a462831ade91ec5c06fd2169d019"}, + {file = "pydocstyle-6.3.0.tar.gz", hash = "sha256:7ce43f0c0ac87b07494eb9c0b462c0b73e6ff276807f204d6b53edc72b7e44e1"}, +] + +[package.dependencies] +importlib-metadata = {version = ">=2.0.0,<5.0.0", markers = "python_version < \"3.8\""} +snowballstemmer = ">=2.2.0" + +[package.extras] +toml = ["tomli (>=1.2.3)"] + +[[package]] +name = "pyflakes" +version = "2.5.0" +description = "passive checker of Python programs" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, + {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, +] + +[[package]] +name = "pygments" +version = "2.16.1" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.7" +files = [ + {file = "Pygments-2.16.1-py3-none-any.whl", hash = "sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692"}, + {file = "Pygments-2.16.1.tar.gz", hash = "sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29"}, +] + +[package.extras] +plugins = ["importlib-metadata"] + +[[package]] +name = "pylint" +version = "2.17.5" +description = "python code static checker" +optional = false +python-versions = ">=3.7.2" +files = [ + {file = "pylint-2.17.5-py3-none-any.whl", hash = "sha256:73995fb8216d3bed149c8d51bba25b2c52a8251a2c8ac846ec668ce38fab5413"}, + {file = "pylint-2.17.5.tar.gz", hash = "sha256:f7b601cbc06fef7e62a754e2b41294c2aa31f1cb659624b9a85bcba29eaf8252"}, +] + +[package.dependencies] +astroid = ">=2.15.6,<=2.17.0-dev0" +colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} +dill = [ + {version = ">=0.2", markers = "python_version < \"3.11\""}, + {version = ">=0.3.6", markers = "python_version >= \"3.11\""}, +] +isort = ">=4.2.5,<6" +mccabe = ">=0.6,<0.8" +platformdirs = ">=2.2.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.10.1" +typing-extensions = {version = ">=3.10.0", markers = "python_version < \"3.10\""} + +[package.extras] +spelling = ["pyenchant (>=3.2,<4.0)"] +testutils = ["gitpython (>3)"] + +[[package]] +name = "pylint-celery" +version = "0.3" +description = "pylint-celery is a Pylint plugin to aid Pylint in recognising and understandingerrors caused when using the Celery library" +optional = false +python-versions = "*" +files = [ + {file = "pylint-celery-0.3.tar.gz", hash = "sha256:41e32094e7408d15c044178ea828dd524beedbdbe6f83f712c5e35bde1de4beb"}, +] + +[package.dependencies] +astroid = ">=1.0" +pylint = ">=1.0" +pylint-plugin-utils = ">=0.2.1" + +[[package]] +name = "pylint-django" +version = "2.5.3" +description = "A Pylint plugin to help Pylint understand the Django web framework" +optional = false +python-versions = "*" +files = [ + {file = "pylint-django-2.5.3.tar.gz", hash = "sha256:0ac090d106c62fe33782a1d01bda1610b761bb1c9bf5035ced9d5f23a13d8591"}, + {file = "pylint_django-2.5.3-py3-none-any.whl", hash = "sha256:56b12b6adf56d548412445bd35483034394a1a94901c3f8571980a13882299d5"}, +] + +[package.dependencies] +pylint = ">=2.0,<3" +pylint-plugin-utils = ">=0.7" + +[package.extras] +for-tests = ["coverage", "django-tables2", "django-tastypie", "factory-boy", "pylint (>=2.13)", "pytest", "wheel"] +with-django = ["Django"] + +[[package]] +name = "pylint-flask" +version = "0.6" +description = "pylint-flask is a Pylint plugin to aid Pylint in recognizing and understanding errors caused when using Flask" +optional = false +python-versions = "*" +files = [ + {file = "pylint-flask-0.6.tar.gz", hash = "sha256:f4d97de2216bf7bfce07c9c08b166e978fe9f2725de2a50a9845a97de7e31517"}, +] + +[package.dependencies] +pylint-plugin-utils = ">=0.2.1" + +[[package]] +name = "pylint-plugin-utils" +version = "0.7" +description = "Utilities and helpers for writing Pylint plugins" +optional = false +python-versions = ">=3.6.2" +files = [ + {file = "pylint-plugin-utils-0.7.tar.gz", hash = "sha256:ce48bc0516ae9415dd5c752c940dfe601b18fe0f48aa249f2386adfa95a004dd"}, + {file = "pylint_plugin_utils-0.7-py3-none-any.whl", hash = "sha256:b3d43e85ab74c4f48bb46ae4ce771e39c3a20f8b3d56982ab17aa73b4f98d535"}, +] + +[package.dependencies] +pylint = ">=1.7" + +[[package]] +name = "pytest" +version = "7.4.2" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.2-py3-none-any.whl", hash = "sha256:1d881c6124e08ff0a1bb75ba3ec0bfd8b5354a01c194ddd5a0a870a48d99b002"}, + {file = "pytest-7.4.2.tar.gz", hash = "sha256:a766259cfab564a2ad52cb1aae1b881a75c3eb7e34ca3779697c23ed47c47069"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "pytest-mock" +version = "3.11.1" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-mock-3.11.1.tar.gz", hash = "sha256:7f6b125602ac6d743e523ae0bfa71e1a697a2f5534064528c6ff84c2f7c2fc7f"}, + {file = "pytest_mock-3.11.1-py3-none-any.whl", hash = "sha256:21c279fff83d70763b05f8874cc9cfb3fcacd6d354247a976f9529d19f9acf39"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-only" +version = "2.0.0" +description = "Use @pytest.mark.only to run a single test" +optional = false +python-versions = ">=3.6.2,<4" +files = [ + {file = "pytest-only-2.0.0.tar.gz", hash = "sha256:0467eefac714a920b2df2e3c1d2fbf61cf2cd65583ccd2e3233f107862a5fc77"}, + {file = "pytest_only-2.0.0-py3-none-any.whl", hash = "sha256:1f344d15d6495ca108b341ca12ca90eb1695bebb3bd3978c8efd4a0e121bdb8f"}, +] + +[package.dependencies] +pytest = {version = ">=7.1", markers = "python_version >= \"3.7\" and python_version < \"4.0\""} + +[[package]] +name = "pywin32-ctypes" +version = "0.2.2" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pywin32-ctypes-0.2.2.tar.gz", hash = "sha256:3426e063bdd5fd4df74a14fa3cf80a0b42845a87e1d1e81f6549f9daec593a60"}, + {file = "pywin32_ctypes-0.2.2-py3-none-any.whl", hash = "sha256:bf490a1a709baf35d688fe0ecf980ed4de11d2b3e37b51e5442587a75d9957e7"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +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-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "questionary" +version = "1.10.0" +description = "Python library to build pretty command line user prompts ⭐️" +optional = false +python-versions = ">=3.6,<4.0" +files = [ + {file = "questionary-1.10.0-py3-none-any.whl", hash = "sha256:fecfcc8cca110fda9d561cb83f1e97ecbb93c613ff857f655818839dac74ce90"}, + {file = "questionary-1.10.0.tar.gz", hash = "sha256:600d3aefecce26d48d97eee936fdb66e4bc27f934c3ab6dd1e292c4f43946d90"}, +] + +[package.dependencies] +prompt_toolkit = ">=2.0,<4.0" + +[package.extras] +docs = ["Sphinx (>=3.3,<4.0)", "sphinx-autobuild (>=2020.9.1,<2021.0.0)", "sphinx-autodoc-typehints (>=1.11.1,<2.0.0)", "sphinx-copybutton (>=0.3.1,<0.4.0)", "sphinx-rtd-theme (>=0.5.0,<0.6.0)"] + +[[package]] +name = "readme-renderer" +version = "37.3" +description = "readme_renderer is a library for rendering \"readme\" descriptions for Warehouse" +optional = false +python-versions = ">=3.7" +files = [ + {file = "readme_renderer-37.3-py3-none-any.whl", hash = "sha256:f67a16caedfa71eef48a31b39708637a6f4664c4394801a7b0d6432d13907343"}, + {file = "readme_renderer-37.3.tar.gz", hash = "sha256:cd653186dfc73055656f090f227f5cb22a046d7f71a841dfa305f55c9a513273"}, +] + +[package.dependencies] +bleach = ">=2.1.0" +docutils = ">=0.13.1" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + +[[package]] +name = "requests" +version = "2.31.0" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.7" +files = [ + {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, + {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "requirements-detector" +version = "1.2.2" +description = "Python tool to find and list requirements of a Python project" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "requirements_detector-1.2.2-py3-none-any.whl", hash = "sha256:d7c60493bf166da3dd59de0e6cb25765e0e32a1931aeae92614034e5786d0bd0"}, + {file = "requirements_detector-1.2.2.tar.gz", hash = "sha256:3642cd7a5b261d79536c36bb7ecacf2adabd902d2e0e42bfb2ba82515da10501"}, +] + +[package.dependencies] +astroid = ">=2.0,<3.0" +packaging = ">=21.3" +semver = ">=3.0.0,<4.0.0" +toml = ">=0.10.2,<0.11.0" + +[[package]] +name = "rfc3986" +version = "2.0.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = ">=3.7" +files = [ + {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, + {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, +] + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "rich" +version = "13.5.3" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "rich-13.5.3-py3-none-any.whl", hash = "sha256:9257b468badc3d347e146a4faa268ff229039d4c2d176ab0cffb4c4fbc73d5d9"}, + {file = "rich-13.5.3.tar.gz", hash = "sha256:87b43e0543149efa1253f485cd845bb7ee54df16c9617b8a893650ab84b4acb6"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "semver" +version = "3.0.1" +description = "Python helper for Semantic Versioning (https://semver.org)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "semver-3.0.1-py3-none-any.whl", hash = "sha256:2a23844ba1647362c7490fe3995a86e097bb590d16f0f32dfc383008f19e4cdf"}, + {file = "semver-3.0.1.tar.gz", hash = "sha256:9ec78c5447883c67b97f98c3b6212796708191d22e4ad30f4570f840171cbce1"}, +] + +[[package]] +name = "setoptconf-tmp" +version = "0.3.1" +description = "A module for retrieving program settings from various sources in a consistant method." +optional = false +python-versions = "*" +files = [ + {file = "setoptconf-tmp-0.3.1.tar.gz", hash = "sha256:e0480addd11347ba52f762f3c4d8afa3e10ad0affbc53e3ffddc0ca5f27d5778"}, + {file = "setoptconf_tmp-0.3.1-py3-none-any.whl", hash = "sha256:76035d5cd1593d38b9056ae12d460eca3aaa34ad05c315b69145e138ba80a745"}, +] + +[package.extras] +yaml = ["pyyaml"] + +[[package]] +name = "setuptools" +version = "68.0.0" +description = "Easily download, build, install, upgrade, and uninstall Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "setuptools-68.0.0-py3-none-any.whl", hash = "sha256:11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f"}, + {file = "setuptools-68.0.0.tar.gz", hash = "sha256:baf1fdb41c6da4cd2eae722e135500da913332ab3f2f5c7d33af9b492acb5235"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-hoverxref (<2)", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (==0.8.3)", "sphinx-reredirects", "sphinxcontrib-towncrier"] +testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pip-run (>=8.8)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] +testing-integration = ["build[virtualenv]", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "snowballstemmer" +version = "2.2.0" +description = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +optional = false +python-versions = "*" +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + +[[package]] +name = "termcolor" +version = "2.2.0" +description = "ANSI color formatting for output in terminal" +optional = false +python-versions = ">=3.7" +files = [ + {file = "termcolor-2.2.0-py3-none-any.whl", hash = "sha256:91ddd848e7251200eac969846cbae2dacd7d71c2871e92733289e7e3666f48e7"}, + {file = "termcolor-2.2.0.tar.gz", hash = "sha256:dfc8ac3f350788f23b2947b3e6cfa5a53b630b612e6cd8965a015a776020b99a"}, +] + +[package.extras] +tests = ["pytest", "pytest-cov"] + +[[package]] +name = "throttlex" +version = "1.0.0" +description = "TimeStam eXtensions for Python" +optional = false +python-versions = "*" +files = [ + {file = "throttlex-1.0.0-py3-none-any.whl", hash = "sha256:a358a321c701a350e55e2591264f15cb85eb0fb09039a9be46d550bfac9f7feb"}, +] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tomlkit" +version = "0.11.8" +description = "Style preserving TOML library" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomlkit-0.11.8-py3-none-any.whl", hash = "sha256:8c726c4c202bdb148667835f68d68780b9a003a9ec34167b6c673b38eff2a171"}, + {file = "tomlkit-0.11.8.tar.gz", hash = "sha256:9330fc7faa1db67b541b28e62018c17d20be733177d290a13b24c62d1614e0c3"}, +] + +[[package]] +name = "tqdm" +version = "4.66.1" +description = "Fast, Extensible Progress Meter" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tqdm-4.66.1-py3-none-any.whl", hash = "sha256:d302b3c5b53d47bce91fea46679d9c3c6508cf6332229aa1e7d8653723793386"}, + {file = "tqdm-4.66.1.tar.gz", hash = "sha256:d88e651f9db8d8551a62556d3cff9e3034274ca5d66e93197cf2490e2dcb69c7"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +dev = ["pytest (>=6)", "pytest-cov", "pytest-timeout", "pytest-xdist"] +notebook = ["ipywidgets (>=6)"] +slack = ["slack-sdk"] +telegram = ["requests"] + +[[package]] +name = "twine" +version = "4.0.2" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.7" +files = [ + {file = "twine-4.0.2-py3-none-any.whl", hash = "sha256:929bc3c280033347a00f847236564d1c52a3e61b1ac2516c97c48f3ceab756d8"}, + {file = "twine-4.0.2.tar.gz", hash = "sha256:9e102ef5fdd5a20661eb88fad46338806c3bd32cf1db729603fe3697b1bc83c8"}, +] + +[package.dependencies] +importlib-metadata = ">=3.6" +keyring = ">=15.1" +pkginfo = ">=1.8.1" +readme-renderer = ">=35.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +rich = ">=12.0.0" +urllib3 = ">=1.26.0" + +[[package]] +name = "typed-ast" +version = "1.5.5" +description = "a fork of Python 2 and 3 ast modules with type comment support" +optional = false +python-versions = ">=3.6" +files = [ + {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, + {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, + {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, + {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, + {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, + {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, + {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, + {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, + {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, + {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, + {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, + {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, + {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, + {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, + {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, + {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, + {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, + {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, + {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, + {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, + {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, + {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, + {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, + {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, + {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, + {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, +] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "urllib3" +version = "2.0.5" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.7" +files = [ + {file = "urllib3-2.0.5-py3-none-any.whl", hash = "sha256:ef16afa8ba34a1f989db38e1dbbe0c302e4289a47856990d0682e374563ce35e"}, + {file = "urllib3-2.0.5.tar.gz", hash = "sha256:13abf37382ea2ce6fb744d4dad67838eec857c9f4f57009891805e0b5e123594"}, +] + +[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"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.21.1" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.7" +files = [ + {file = "virtualenv-20.21.1-py3-none-any.whl", hash = "sha256:09ddbe1af0c8ed2bb4d6ed226b9e6415718ad18aef9fa0ba023d96b7a8356049"}, + {file = "virtualenv-20.21.1.tar.gz", hash = "sha256:4c104ccde994f8b108163cf9ba58f3d11511d9403de87fb9b4f52bf33dbc8668"}, +] + +[package.dependencies] +distlib = ">=0.3.6,<1" +filelock = ">=3.4.1,<4" +importlib-metadata = {version = ">=4.8.3", markers = "python_version < \"3.8\""} +platformdirs = ">=2.4,<4" + +[package.extras] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] + +[[package]] +name = "wcwidth" +version = "0.2.6" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.6-py2.py3-none-any.whl", hash = "sha256:795b138f6875577cd91bba52baf9e445cd5118fd32723b460e30a0af30ea230e"}, + {file = "wcwidth-0.2.6.tar.gz", hash = "sha256:a5220780a404dbe3353789870978e472cfe477761f06ee55077256e509b156d0"}, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[[package]] +name = "wrapt" +version = "1.15.0" +description = "Module for decorators, wrappers and monkey patching." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" +files = [ + {file = "wrapt-1.15.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ca1cccf838cd28d5a0883b342474c630ac48cac5df0ee6eacc9c7290f76b11c1"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e826aadda3cae59295b95343db8f3d965fb31059da7de01ee8d1c40a60398b29"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5fc8e02f5984a55d2c653f5fea93531e9836abbd84342c1d1e17abc4a15084c2"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:96e25c8603a155559231c19c0349245eeb4ac0096fe3c1d0be5c47e075bd4f46"}, + {file = "wrapt-1.15.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:40737a081d7497efea35ab9304b829b857f21558acfc7b3272f908d33b0d9d4c"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:f87ec75864c37c4c6cb908d282e1969e79763e0d9becdfe9fe5473b7bb1e5f09"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:1286eb30261894e4c70d124d44b7fd07825340869945c79d05bda53a40caa079"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:493d389a2b63c88ad56cdc35d0fa5752daac56ca755805b1b0c530f785767d5e"}, + {file = "wrapt-1.15.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:58d7a75d731e8c63614222bcb21dd992b4ab01a399f1f09dd82af17bbfc2368a"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:21f6d9a0d5b3a207cdf7acf8e58d7d13d463e639f0c7e01d82cdb671e6cb7923"}, + {file = "wrapt-1.15.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce42618f67741d4697684e501ef02f29e758a123aa2d669e2d964ff734ee00ee"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:41d07d029dd4157ae27beab04d22b8e261eddfc6ecd64ff7000b10dc8b3a5727"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54accd4b8bc202966bafafd16e69da9d5640ff92389d33d28555c5fd4f25ccb7"}, + {file = "wrapt-1.15.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbfbca668dd15b744418265a9607baa970c347eefd0db6a518aaf0cfbd153c0"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:76e9c727a874b4856d11a32fb0b389afc61ce8aaf281ada613713ddeadd1cfec"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e20076a211cd6f9b44a6be58f7eeafa7ab5720eb796975d0c03f05b47d89eb90"}, + {file = "wrapt-1.15.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:a74d56552ddbde46c246b5b89199cb3fd182f9c346c784e1a93e4dc3f5ec9975"}, + {file = "wrapt-1.15.0-cp310-cp310-win32.whl", hash = "sha256:26458da5653aa5b3d8dc8b24192f574a58984c749401f98fff994d41d3f08da1"}, + {file = "wrapt-1.15.0-cp310-cp310-win_amd64.whl", hash = "sha256:75760a47c06b5974aa5e01949bf7e66d2af4d08cb8c1d6516af5e39595397f5e"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ba1711cda2d30634a7e452fc79eabcadaffedf241ff206db2ee93dd2c89a60e7"}, + {file = "wrapt-1.15.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:56374914b132c702aa9aa9959c550004b8847148f95e1b824772d453ac204a72"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a89ce3fd220ff144bd9d54da333ec0de0399b52c9ac3d2ce34b569cf1a5748fb"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3bbe623731d03b186b3d6b0d6f51865bf598587c38d6f7b0be2e27414f7f214e"}, + {file = "wrapt-1.15.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3abbe948c3cbde2689370a262a8d04e32ec2dd4f27103669a45c6929bcdbfe7c"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b67b819628e3b748fd3c2192c15fb951f549d0f47c0449af0764d7647302fda3"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:7eebcdbe3677e58dd4c0e03b4f2cfa346ed4049687d839adad68cc38bb559c92"}, + {file = "wrapt-1.15.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:74934ebd71950e3db69960a7da29204f89624dde411afbfb3b4858c1409b1e98"}, + {file = "wrapt-1.15.0-cp311-cp311-win32.whl", hash = "sha256:bd84395aab8e4d36263cd1b9308cd504f6cf713b7d6d3ce25ea55670baec5416"}, + {file = "wrapt-1.15.0-cp311-cp311-win_amd64.whl", hash = "sha256:a487f72a25904e2b4bbc0817ce7a8de94363bd7e79890510174da9d901c38705"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:4ff0d20f2e670800d3ed2b220d40984162089a6e2c9646fdb09b85e6f9a8fc29"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9ed6aa0726b9b60911f4aed8ec5b8dd7bf3491476015819f56473ffaef8959bd"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_i686.whl", hash = "sha256:896689fddba4f23ef7c718279e42f8834041a21342d95e56922e1c10c0cc7afb"}, + {file = "wrapt-1.15.0-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:75669d77bb2c071333417617a235324a1618dba66f82a750362eccbe5b61d248"}, + {file = "wrapt-1.15.0-cp35-cp35m-win32.whl", hash = "sha256:fbec11614dba0424ca72f4e8ba3c420dba07b4a7c206c8c8e4e73f2e98f4c559"}, + {file = "wrapt-1.15.0-cp35-cp35m-win_amd64.whl", hash = "sha256:fd69666217b62fa5d7c6aa88e507493a34dec4fa20c5bd925e4bc12fce586639"}, + {file = "wrapt-1.15.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b0724f05c396b0a4c36a3226c31648385deb6a65d8992644c12a4963c70326ba"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbeccb1aa40ab88cd29e6c7d8585582c99548f55f9b2581dfc5ba68c59a85752"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38adf7198f8f154502883242f9fe7333ab05a5b02de7d83aa2d88ea621f13364"}, + {file = "wrapt-1.15.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:578383d740457fa790fdf85e6d346fda1416a40549fe8db08e5e9bd281c6a475"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:a4cbb9ff5795cd66f0066bdf5947f170f5d63a9274f99bdbca02fd973adcf2a8"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:af5bd9ccb188f6a5fdda9f1f09d9f4c86cc8a539bd48a0bfdc97723970348418"}, + {file = "wrapt-1.15.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:b56d5519e470d3f2fe4aa7585f0632b060d532d0696c5bdfb5e8319e1d0f69a2"}, + {file = "wrapt-1.15.0-cp36-cp36m-win32.whl", hash = "sha256:77d4c1b881076c3ba173484dfa53d3582c1c8ff1f914c6461ab70c8428b796c1"}, + {file = "wrapt-1.15.0-cp36-cp36m-win_amd64.whl", hash = "sha256:077ff0d1f9d9e4ce6476c1a924a3332452c1406e59d90a2cf24aeb29eeac9420"}, + {file = "wrapt-1.15.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:5c5aa28df055697d7c37d2099a7bc09f559d5053c3349b1ad0c39000e611d317"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3a8564f283394634a7a7054b7983e47dbf39c07712d7b177b37e03f2467a024e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:780c82a41dc493b62fc5884fb1d3a3b81106642c5c5c78d6a0d4cbe96d62ba7e"}, + {file = "wrapt-1.15.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e169e957c33576f47e21864cf3fc9ff47c223a4ebca8960079b8bd36cb014fd0"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:b02f21c1e2074943312d03d243ac4388319f2456576b2c6023041c4d57cd7019"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:f2e69b3ed24544b0d3dbe2c5c0ba5153ce50dcebb576fdc4696d52aa22db6034"}, + {file = "wrapt-1.15.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d787272ed958a05b2c86311d3a4135d3c2aeea4fc655705f074130aa57d71653"}, + {file = "wrapt-1.15.0-cp37-cp37m-win32.whl", hash = "sha256:02fce1852f755f44f95af51f69d22e45080102e9d00258053b79367d07af39c0"}, + {file = "wrapt-1.15.0-cp37-cp37m-win_amd64.whl", hash = "sha256:abd52a09d03adf9c763d706df707c343293d5d106aea53483e0ec8d9e310ad5e"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cdb4f085756c96a3af04e6eca7f08b1345e94b53af8921b25c72f096e704e145"}, + {file = "wrapt-1.15.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:230ae493696a371f1dbffaad3dafbb742a4d27a0afd2b1aecebe52b740167e7f"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63424c681923b9f3bfbc5e3205aafe790904053d42ddcc08542181a30a7a51bd"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d6bcbfc99f55655c3d93feb7ef3800bd5bbe963a755687cbf1f490a71fb7794b"}, + {file = "wrapt-1.15.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c99f4309f5145b93eca6e35ac1a988f0dc0a7ccf9ccdcd78d3c0adf57224e62f"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b130fe77361d6771ecf5a219d8e0817d61b236b7d8b37cc045172e574ed219e6"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:96177eb5645b1c6985f5c11d03fc2dbda9ad24ec0f3a46dcce91445747e15094"}, + {file = "wrapt-1.15.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5fe3e099cf07d0fb5a1e23d399e5d4d1ca3e6dfcbe5c8570ccff3e9208274f7"}, + {file = "wrapt-1.15.0-cp38-cp38-win32.whl", hash = "sha256:abd8f36c99512755b8456047b7be10372fca271bf1467a1caa88db991e7c421b"}, + {file = "wrapt-1.15.0-cp38-cp38-win_amd64.whl", hash = "sha256:b06fa97478a5f478fb05e1980980a7cdf2712015493b44d0c87606c1513ed5b1"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2e51de54d4fb8fb50d6ee8327f9828306a959ae394d3e01a1ba8b2f937747d86"}, + {file = "wrapt-1.15.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0970ddb69bba00670e58955f8019bec4a42d1785db3faa043c33d81de2bf843c"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76407ab327158c510f44ded207e2f76b657303e17cb7a572ffe2f5a8a48aa04d"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cd525e0e52a5ff16653a3fc9e3dd827981917d34996600bbc34c05d048ca35cc"}, + {file = "wrapt-1.15.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d37ac69edc5614b90516807de32d08cb8e7b12260a285ee330955604ed9dd29"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:078e2a1a86544e644a68422f881c48b84fef6d18f8c7a957ffd3f2e0a74a0d4a"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:2cf56d0e237280baed46f0b5316661da892565ff58309d4d2ed7dba763d984b8"}, + {file = "wrapt-1.15.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7dc0713bf81287a00516ef43137273b23ee414fe41a3c14be10dd95ed98a2df9"}, + {file = "wrapt-1.15.0-cp39-cp39-win32.whl", hash = "sha256:46ed616d5fb42f98630ed70c3529541408166c22cdfd4540b88d5f21006b0eff"}, + {file = "wrapt-1.15.0-cp39-cp39-win_amd64.whl", hash = "sha256:eef4d64c650f33347c1f9266fa5ae001440b232ad9b98f1f43dfe7a79435c0a6"}, + {file = "wrapt-1.15.0-py3-none-any.whl", hash = "sha256:64b1df0f83706b4ef4cfb4fb0e4c2669100fd7ecacfb59e091fad300d4e04640"}, + {file = "wrapt-1.15.0.tar.gz", hash = "sha256:d06730c6aed78cee4126234cf2d071e01b44b915e725a6cb439a879ec9754a3a"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.7.2,<4.0.0" +content-hash = "203bd7b16a80690fdd4eccc3d221f114858055e9232520d34debc9548d01fdd2" diff --git a/poetry.toml b/poetry.toml new file mode 100644 index 0000000..7ccf722 --- /dev/null +++ b/poetry.toml @@ -0,0 +1,6 @@ +# Low level configuration for how the `poetry` tool should work for this project. +# You should rarely need to change this. See `pyproject.toml` for the primary project configuration. + +[virtualenvs] +in-project = true +virtualenvs.path = "./.venv" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3805264 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,102 @@ +[tool.poetry] +name = "streamerate" +version = "1.0.3" # do not edit manually. kept in sync with `tool.commitizen` config via automation +description = "streamerate: a fluent and expressive Python library for chainable iterable processing, inspired by Java 8 streams." +authors = ["Andrei Suiu "] +repository = "https://github.com/asuiu/streamerate" +readme = "README.md" +license = "MIT" + +[tool.poetry.dependencies] +python = ">=3.8,<4.0.0" +tqdm = ">=4.62.0" +throttlex = ">=1.0.0" +eventlet = ">=0.20.0" + + +[tool.poetry.dev-dependencies] +pytest = "~7.4.2" +pytest-mock = "~3.11.1" +invoke = "~2.0" +black = ">=22.12" +pycodestyle = "~2.10" +pydocstyle = "~6.3" +#mypy = "~1.5.1" +pylint = ">=2.17.5" +termcolor = "~2.2.0" +commitizen = "~2.42.1" +tomlkit = "~0.11.6" +pytest-only = "~=2.0.0" +coverage = { extras = ["toml"], version = "~7.2.1" } +pytest-cov = "~4.0.0" +#scikit-build = "~0.16.7" +prospector = ">=1.10.1" +pre-commit = ">=2.21.0" +twine = ">=4.0.2" + +[tool.poetry.scripts] +test = "tasks:test" +reformat = "tasks:reformat" +lint = "tasks:lint" +typecheck = "tasks:typecheck" +verify-all = "tasks:verify_all" +find-releasable-changes = "tasks:find_releasable_changes" +prepare-release = "tasks:prepare_release" +debug-auto-git-tag = "tasks:debug_auto_git_tag" + +[tool.black] +line-length = 160 +include = '\.pyi?$' +default_language_version = '3.8' + +[tool.pylint.master] +#ignore="tests,test_integrations" +ignore-patterns = ["test_.*"] +load-plugins = ["pylint.extensions.no_self_use"] + +[tool.pylint.messages_control] +max-line-length = 160 +disable = ["import-error", + "missing-module-docstring", + "missing-class-docstring", + "invalid-name", + "no-name-in-module", + "missing-function-docstring", + "too-few-public-methods", + "too-many-instance-attributes", + "logging-fstring-interpolation"] +output-format = "colorized" +max-locals = 25 +max-args = 10 +enable = "useless-suppression" + +[tool.ruff] +# Enable Pyflakes `E` and `F` codes by default. +select = ["E", "F"] +ignore = ["E501"] + + +# Allow autofix for all enabled rules (when `--fix`) is provided. +fixable = ["A", "B", "C", "D", "E", "F"] +unfixable = [] + + +[tool.commitizen] +name = "cz_conventional_commits" +version = "1.0.2" # do not edit manually. kept in sync with `tool.poetry` config via automation +tag_format = "v$version" + +# Same as Black. +line-length = 160 + +[tool.coverage.run] +branch = true + +[tool.coverage.report] +exclude_also = [ + "if TYPE_CHECKING:" +] + +[build-system] +requires = ["poetry>=1.3"] +build-backend = "poetry.masonry.api" diff --git a/requirements.txt b/requirements.txt index fa15a3d..ab5c9a7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ -tqdm>=4.62.0;python_version>="3" +eventlet>=0.20.0;python_version>="3" pydantic>=1.8.2;python_version>="3" tblib>=1.7.0;python_version>="3" -throttlex>=1.0.0 \ No newline at end of file +throttlex>=1.0.0 +tqdm>=4.62.0;python_version>="3" diff --git a/setup.py b/setup.py deleted file mode 100644 index 8fb1ad9..0000000 --- a/setup.py +++ /dev/null @@ -1,110 +0,0 @@ -from codecs import open -from os import path - -from setuptools import setup - -__author__ = 'ASU' - -# Bump up this version -VERSION = '1.0.2' - -basedir = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(basedir, 'README.md'), encoding='utf-8') as f: - long_description = f.read() - -with open("requirements.txt") as fp: - install_requires = fp.read().strip().split("\n") - -print("List of dependencies : {0}".format(str(install_requires))) - -parameters = dict( - name='streamerate', - - # Versions should comply with PEP440. For a discussion on single-sourcing - # the version across setup.py and the project code, see - # https://packaging.python.org/en/latest/single_source_version.html - version=VERSION, - - description='streamerate: a fluent and expressive Python library for chainable iterable processing, inspired by Java 8 streams.', - long_description=long_description, - long_description_content_type="text/markdown", - - # The project's main homepage. - url='https://github.com/asuiu/streamerate', - - author='Andrei Suiu', - author_email='andrei.suiu@gmail.com', - - license='MIT', - - classifiers=[ - # How mature is this project? Common values are - # 3 - Alpha - # 4 - Beta - # 5 - Production/Stable - 'Development Status :: 5 - Production/Stable', - - # Indicate who your project is intended for - 'Intended Audience :: Developers', - 'Topic :: System :: Logging', - 'Topic :: Software Development :: Libraries', - 'Topic :: Internet :: Log Analysis', - - # Pick your license as you wish (should match "license" above) - 'License :: OSI Approved :: Apache Software License', - - # Specify the Python versions you support basedir. - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - "Programming Language :: Python :: 3.9", - "Programming Language :: Python :: 3.10", - "Programming Language :: Python :: 3.11", - "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: Implementation :: PyPy" - ], - - # What does your project relate to? - keywords='stream itertools fluent functional chainable iterable processing', - - # You can just specify the packages manually basedir if your project is - # simple. Or you can use find_packages(). - # packages=find_packages(exclude=['dist', 'docs', 'build', 'tests']), - packages=['streamerate'], - - # Alternatively, if you want to distribute just a my_module.py, uncomment - # this: - # py_modules=["my_module"], - - # List run-time dependencies basedir. These will be installed by pip when - # your project is installed. For an analysis of "install_requires" vs pip's - # requirements files see: - # https://packaging.python.org/en/latest/requirements.html - install_requires=install_requires, - - # List additional groups of dependencies basedir (e.g. development - # dependencies). You can install these using the following syntax, - # for example: - # $ pip install -e .[dev,test] - extras_require={}, - - # If there are data files included in your packages that need to be - # installed, specify them basedir. If using Python 2.6 or less, then these - # have to be included in MANIFEST.in as well. - package_data={}, - - # Although 'package_data' is the preferred approach, in some case you may - # need to place data files outside of your packages. See: - # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa - # In this case, 'data_file' will be installed into '/my_data' - data_files=[], - - # To provide executable scripts, use entry points in preference to the - # "scripts" keyword. Entry points provide cross-platform support and allow - # pip to create the appropriate form of executable for the target platform. - entry_points={}, -) - -setup(**parameters) diff --git a/streamerate/streams.py b/streamerate/streams.py index 328a7e2..9cba2bb 100644 --- a/streamerate/streams.py +++ b/streamerate/streams.py @@ -1,6 +1,8 @@ # Author: ASU -- # Purpose: utility library for >=Python3.8 +# pylint: disable=too-many-lines import collections +import copy import io import itertools import math @@ -19,19 +21,38 @@ from queue import Queue from random import shuffle from types import GeneratorType -from typing import AbstractSet, Any, BinaryIO, Callable, Dict, Generator, Iterable, Iterator, List, Mapping, MutableSet, \ - NamedTuple, Optional, overload, Set, Tuple, TypeVar, Union - +from typing import ( + AbstractSet, + Any, + BinaryIO, + Callable, + Dict, + Generator, + Iterable, + Iterator, + List, + Mapping, + MutableSet, + NamedTuple, + Optional, + Set, + Tuple, + TypeVar, + Union, + overload, +) + +from eventlet import GreenPool from tblib import pickling_support from throttlex import Throttler from tqdm import tqdm -__author__ = 'andrei.suiu@gmail.com' +__author__ = "andrei.suiu@gmail.com" -_K = TypeVar('_K') -_V = TypeVar('_V') -_T = TypeVar('_T') -_T_co = TypeVar('_T_co', covariant=True) +_K = TypeVar("_K") +_V = TypeVar("_V") +_T = TypeVar("_T") +_T_co = TypeVar("_T_co", covariant=True) _IDENTITY_FUNC: Callable[[_T], _T] = lambda _: _ @@ -41,8 +62,7 @@ def __init__(self, f: Callable[[], Iterable[_K]]): if callable(f): self._f = f else: - raise TypeError( - "Argument f to %s should be callable, but f.__class__=%s" % (str(self.__class__), str(f.__class__))) + raise TypeError(f"Argument f to {self.__class__!s} should be callable, but f.__class__={f.__class__!s}") def __iter__(self) -> Iterator[_T_co]: return iter(self._f()) @@ -63,7 +83,6 @@ class _QElement(NamedTuple): class TqdmMapper: - def __init__(self, *args, **kwargs) -> None: """ :param args: same args that are passed to tqdm @@ -75,24 +94,21 @@ def __call__(self, el: _K) -> _K: self._tqdm.update() return el + class _IStream(Iterable[_K], ABC): + # pylint: disable=too-many-public-methods @staticmethod - def _init_itr(itr: Optional[Union[Iterator[_K], Callable[[], Iterable[_K]]]] = None) -> Tuple[ - Optional[Iterable[_K]], - Optional[Callable[[], Iterable[_K]]] - ]: + def _init_itr(itr: Optional[Union[Iterator[_K], Callable[[], Iterable[_K]]]] = None) -> Tuple[Optional[Iterable[_K]], Optional[Callable[[], Iterable[_K]]]]: _f = None if itr is None: _itr = [] - elif isinstance(itr, (abc.Iterable, abc.Iterator)) or hasattr(itr, '__iter__') or hasattr(itr, '__getitem__'): + elif isinstance(itr, (abc.Iterable, abc.Iterator)) or hasattr(itr, "__iter__") or hasattr(itr, "__getitem__"): _itr = itr elif callable(itr): _f = itr _itr = None else: - raise TypeError( - "Argument f to _IStream should be callable or iterable, but itr.__class__=%s" % ( - str(itr.__class__))) + raise TypeError(f"Argument f to _IStream should be callable or iterable, but itr.__class__={itr.__class__!s}") return _itr, _f @staticmethod @@ -105,7 +121,7 @@ def __fastmap_thread(f, qin, qout): try: newEl = f(el) qout.put(newEl) - except: + except Exception: # pylint: disable=broad-except qout.put(_MapException(sys.exc_info())) @staticmethod @@ -123,7 +139,7 @@ def __mtmap_thread(f, qin, qout): try: newEl = f(q_el.el) qout.put(_QElement(q_el.i, newEl)) - except: + except Exception: # pylint: disable=broad-except qout.put(_MapException(sys.exc_info())) @staticmethod @@ -138,10 +154,11 @@ def __fastFlatMap_thread(f, qin, qout): newItr = f(itr) for el in newItr: qout.put(el) - except: + except Exception: # pylint: disable=broad-except qout.put(_MapException(sys.exc_info())) def __fastmap_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: int): + # pylint: disable=too-many-branches qin = Queue(bufferSize) qout = Queue(max(bufferSize, poolSize + 1)) # max() is needed to not block when exiting @@ -190,6 +207,7 @@ def __fastmap_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: t.join() def __mtmap_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: int): + # pylint: disable=too-many-branches, too-many-statements qin = Queue(bufferSize) qout = Queue(max(bufferSize, poolSize + 1)) # max() is needed to not block when exiting @@ -270,14 +288,12 @@ def __fastFlatMap_input_thread(itr: Iterator[_K], qin: Queue): except StopIteration: qin.put(_EndQueue()) return - else: - qin.put(el) + qin.put(el) def __fastFlatMap_generator(self, predicate, poolSize: int, bufferSize: int): qin = Queue(bufferSize) qout = Queue(bufferSize * 2) - threadPool = [threading.Thread(target=_IStream.__fastFlatMap_thread, args=(predicate, qin, qout)) for i in - range(poolSize)] + threadPool = [threading.Thread(target=_IStream.__fastFlatMap_thread, args=(predicate, qin, qout)) for i in range(poolSize)] for t in threadPool: t.start() i = 0 @@ -317,7 +333,7 @@ def exc_info_decorator(f: Callable[[_K], _V], el: _K) -> Union[_MapException, _V """This decorates f to pass the exception traceback properly""" try: return f(el) - except Exception as e: + except Exception as e: # pylint: disable=broad-except,broad-exception-caught pickling_support.install(e) return _MapException(sys.exc_info()) @@ -331,8 +347,16 @@ def __mp_pool_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: p.close() p.join() - def __mp_fast_pool_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: int - ) -> Generator[_V, None, None]: + def __gt_pool_generator(self, f: Callable[[_K], _V], poolSize: int) -> Generator[_V, None, None]: + p = GreenPool(poolSize) + decorated_f_with_exc_passing = partial(self.exc_info_decorator, f) + for el in p.imap(decorated_f_with_exc_passing, self): + if isinstance(el, _MapException): + raise el.exc_info[0](el.exc_info[1]).with_traceback(el.exc_info[2]) + yield el + p.waitall() + + def __mp_fast_pool_generator(self, f: Callable[[_K], _V], poolSize: int, bufferSize: int) -> Generator[_V, None, None]: p = Pool(poolSize) try: decorated_f_with_exc_passing = partial(self.exc_info_decorator, f) @@ -366,33 +390,31 @@ def __add_observer_generator(self, observer: Callable[[_K], None]) -> Iterator[_ observer(el) yield el - def map(self, f: Callable[[_K], _V]) -> 'stream[_V]': + def map(self, f: Callable[[_K], _V]) -> "stream[_V]": return stream(partial(map, f, self)) - def starmap(self, f: Callable[[_K], _V]) -> 'stream[_V]': + def starmap(self, f: Callable[[_K], _V]) -> "stream[_V]": return stream(partial(itertools.starmap, f, self)) - def mpmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), - bufferSize: Optional[int] = 1) -> 'stream[_V]': + def mpmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), bufferSize: Optional[int] = 1) -> "stream[_V]": """ Parallel ordered map using multiprocessing.Pool.imap :param poolSize: number of processes in Pool :param bufferSize: passed as chunksize param to imap() """ # Validations - if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2 ** 12: - raise ValueError("poolSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) - elif poolSize == 1: + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize}") + if poolSize == 1: return self.map(f) if bufferSize is None: bufferSize = poolSize * 2 - if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2 ** 12: - raise ValueError("bufferSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) + if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2**12: + raise ValueError(f"bufferSize should be an integer between 1 and 2^12. Received: {poolSize!s}") return stream(self.__mp_pool_generator(f, poolSize, bufferSize)) - def mpstarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), - bufferSize: Optional[int] = 1) -> 'stream[_V]': + def mpstarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), bufferSize: Optional[int] = 1) -> "stream[_V]": """ Parallel unordered map using multiprocessing.Pool.imap_unordered :param poolSize: number of processes in Pool @@ -400,22 +422,21 @@ def mpstarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_coun """ return self.mpmap(partial(self._star_mapper, f), poolSize, bufferSize) - def mpfastmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), - bufferSize: Optional[int] = 1) -> 'stream[_V]': + def mpfastmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), bufferSize: Optional[int] = 1) -> "stream[_V]": """ Parallel unordered map using multiprocessing.Pool.imap_unordered :param poolSize: number of processes in Pool :param bufferSize: passed as chunksize param to imap_unordered(), so it default to 1 as imap_unordered """ # Validations - if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2 ** 12: - raise ValueError("poolSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) - elif poolSize == 1: + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize!s}") + if poolSize == 1: return self.map(f) if bufferSize is None: bufferSize = poolSize * 2 - if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2 ** 12: - raise ValueError("bufferSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) + if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2**12: + raise ValueError(f"bufferSize should be an integer between 1 and 2^12. Received: {poolSize!s}") return stream(self.__mp_fast_pool_generator(f, poolSize, bufferSize)) @@ -423,8 +444,7 @@ def mpfastmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_coun def _star_mapper(f, el): return f(*el) - def mpfaststarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), - bufferSize: Optional[int] = 1) -> 'stream[_V]': + def mpfaststarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_count(), bufferSize: Optional[int] = 1) -> "stream[_V]": """ Parallel unordered map using multiprocessing.Pool.imap_unordered :param poolSize: number of processes in Pool @@ -432,8 +452,7 @@ def mpfaststarmap(self, f: Callable[[_K], _V], poolSize: Union[int, Pool] = cpu_ """ return self.mpfastmap(partial(_IStream._star_mapper, f), poolSize, bufferSize) - def fastmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), - bufferSize: Optional[int] = None) -> 'stream[_V]': + def fastmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), bufferSize: Optional[int] = None) -> "stream[_V]": """ Parallel unordered map using multithreaded pool. It spawns at most poolSize threads and applies the f function. @@ -441,19 +460,18 @@ def fastmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), It's most usefull for I/O or CPU intensive consuming functions. :param poolSize: number of threads to spawn """ - if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2 ** 12: - raise ValueError("poolSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) - elif poolSize == 1: + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize!s}") + if poolSize == 1: return self.map(f) if bufferSize is None: bufferSize = poolSize - if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2 ** 12: - raise ValueError("bufferSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) + if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2**12: + raise ValueError(f"bufferSize should be an integer between 1 and 2^12. Received: {poolSize!s}") return stream(ItrFromFunc(lambda: self.__fastmap_generator(f, poolSize, bufferSize))) - def faststarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), - bufferSize: Optional[int] = None) -> 'stream[_V]': + def faststarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), bufferSize: Optional[int] = None) -> "stream[_V]": """ Parallel unordered starmap using multithreaded pool. It spawns at most poolSize threads and applies the f function. @@ -463,8 +481,7 @@ def faststarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), """ return self.fastmap(lambda el: f(*el), poolSize, bufferSize) - def mtmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), - bufferSize: Optional[int] = None) -> 'stream[_V]': + def mtmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), bufferSize: Optional[int] = None) -> "stream[_V]": """ Parallel ORDERED map using multithreaded pool. It spawns at most poolSize threads and applies the f function. @@ -472,19 +489,30 @@ def mtmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), It's most usefull for I/O or CPU intensive consuming functions. :param poolSize: number of threads to spawn """ - if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2 ** 12: - raise ValueError("poolSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) - elif poolSize == 1: + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize!s}") + if poolSize == 1: return self.map(f) if bufferSize is None: bufferSize = poolSize - if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2 ** 12: - raise ValueError("bufferSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) + if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2**12: + raise ValueError(f"bufferSize should be an integer between 1 and 2^12. Received: {poolSize!s}") return stream(ItrFromFunc(lambda: self.__mtmap_generator(f, poolSize, bufferSize))) - def mtstarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), - bufferSize: Optional[int] = None) -> 'stream[_V]': + def gtmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count()) -> "stream[_V]": + """ + Parallel ordered map using Green Threads (Greenlets) through the eventlet library. + :param poolSize: number of greenlets in Pool + """ + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize!s}") + if poolSize == 1: + return self.map(f) + + return stream(ItrFromFunc(lambda: self.__gt_pool_generator(f, poolSize))) + + def mtstarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), bufferSize: Optional[int] = None) -> "stream[_V]": """ Parallel ORDERED map using multithreaded pool. It spawns at most poolSize threads and applies the f function. @@ -494,25 +522,36 @@ def mtstarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count(), """ return self.mtmap(lambda el: f(*el), poolSize, bufferSize) - def fastFlatMap(self, predicate: Callable[[_K], Iterable[_V]] = _IDENTITY_FUNC, poolSize: int = cpu_count(), - bufferSize: Optional[int] = None) -> 'stream[_V]': - if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2 ** 12: - raise ValueError("poolSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) - elif poolSize == 1: + def gtstarmap(self, f: Callable[[_K], _V], poolSize: int = cpu_count()) -> "stream[_V]": + """ + Parallel ORDERED map using eventlet.Pool with Green threads. + It spawns at most poolSize green threads and applies the f function. + The elements in the result stream appears in the same order as at input. + It's usefull only for I/O intensive consuming functions (and please not that it has to use eventlet.sleep in order to benefit from green threads). + :param poolSize: number of threads to spawn + """ + return self.gtmap(lambda el: f(*el), poolSize) + + def fastFlatMap( + self, predicate: Callable[[_K], Iterable[_V]] = _IDENTITY_FUNC, poolSize: int = cpu_count(), bufferSize: Optional[int] = None + ) -> "stream[_V]": + if not isinstance(poolSize, int) or poolSize <= 0 or poolSize > 2**12: + raise ValueError(f"poolSize should be an integer between 1 and 2^12. Received: {poolSize!s}") + if poolSize == 1: return self.flatMap(predicate) if bufferSize is None: bufferSize = poolSize - if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2 ** 12: - raise ValueError("bufferSize should be an integer between 1 and 2^12. Received: %s" % str(poolSize)) + if not isinstance(bufferSize, int) or bufferSize <= 0 or bufferSize > 2**12: + raise ValueError(f"bufferSize should be an integer between 1 and 2^12. Received: {poolSize!s}") return stream(lambda: self.__fastFlatMap_generator(predicate, poolSize, bufferSize)) - def map_stream(self, f: Callable[['_IStream[_K]'], _T]) -> _T: + def map_stream(self, f: Callable[["_IStream[_K]"], _T]) -> _T: return f(self) - def enumerate(self) -> 'stream[Tuple[int,_K]]': + def enumerate(self) -> "stream[Tuple[int,_K]]": return stream(zip(range(0, sys.maxsize), self)) - def flatMap(self, predicate: Callable[[_K], Iterable[_V]] = _IDENTITY_FUNC) -> 'stream[_V]': + def flatMap(self, predicate: Callable[[_K], Iterable[_V]] = _IDENTITY_FUNC) -> "stream[_V]": """ :param predicate: predicate is a function that will receive elements of self collection and return an iterable By default predicate is an identity function @@ -526,20 +565,20 @@ def for_each(self, f: Callable[[_K], None]) -> None: for el in self: f(el) - def add_observer(self, f: Callable[[_K], None]) -> 'stream[_K]': + def add_observer(self, f: Callable[[_K], None]) -> "stream[_K]": """ :param f: f is observer that will receive elements of self collection and return None :return: will return stream of objects of the same type of elements from the stream """ return stream(ItrFromFunc(lambda: self.__add_observer_generator(f))) - def filter(self, predicate: Optional[Callable[[_K], bool]] = None) -> 'stream[_K]': + def filter(self, predicate: Optional[Callable[[_K], bool]] = None) -> "stream[_K]": """ :param predicate: If predicate is None, return the items that are true. """ return stream(ItrFromFunc(lambda: filter(predicate, self))) - def starfilter(self, predicate: Callable[[_K], bool]) -> 'stream[_K]': + def starfilter(self, predicate: Callable[[_K], bool]) -> "stream[_K]": """ :param predicate: Applies predicate unpacks the current item when calling predicate function. If predicate is None, returns the items that are true, @@ -547,9 +586,9 @@ def starfilter(self, predicate: Callable[[_K], bool]) -> 'stream[_K]': """ return self.filter(lambda el: predicate(*el)) - def reversed(self) -> 'stream[_K]': + def reversed(self) -> "stream[_K]": try: - return stream(self.__reversed__()) + return stream(reversed(self)) except AttributeError: return stream(lambda: reversed(self.toList())) @@ -562,28 +601,28 @@ def exists(self, f: Callable[[_K], bool]) -> bool: return True return False - def keyBy(self, keyfunc: Callable[[_K], _V] = _IDENTITY_FUNC) -> 'stream[Tuple[_K, _V]]': + def keyBy(self, keyfunc: Callable[[_K], _V] = _IDENTITY_FUNC) -> "stream[Tuple[_K, _V]]": """ :param keyfunc: function to map values to keys :return: stream of Key, Value pairs """ return self.map(lambda h: (keyfunc(h), h)) - def keystream(self: 'stream[Tuple[_T,_V]]') -> 'stream[_T]': + def keystream(self: "stream[Tuple[_T,_V]]") -> "stream[_T]": """ Applies only on streams of 2-uples :return: stream consisted of first element of tuples """ return self.map(itemgetter(0)) - def values(self: 'stream[Tuple[_T,_V]]') -> 'stream[_V]': + def values(self: "stream[Tuple[_T,_V]]") -> "stream[_V]": """ Applies only on streams of 2-uples :return: stream consisted of second element of tuples """ return self.map(itemgetter(1)) - def groupBy(self, keyfunc: Callable[[_K], _T] = _IDENTITY_FUNC) -> 'slist[Tuple[_T, slist[_K]]]': + def groupBy(self, keyfunc: Callable[[_K], _T] = _IDENTITY_FUNC) -> "slist[Tuple[_T, slist[_K]]]": """ groupBy([keyfunc]) -> Make a slist with consecutive keys and groups from the iterable. The iterable needs not to be sorted on the same key function, but the keyfunction need to return hashable objects. @@ -600,7 +639,7 @@ def __order_key_func(order_fn: Callable[[_K], _T], x: Tuple[int, _K]): return x[0] - order_fn(x[1]) @classmethod - def __group_consecutive_generator(cls, itr, order_fn: Callable[[_K], _T] = lambda x: x) -> 'Generator[Tuple[_T, stream[_K]],None,None]': + def __group_consecutive_generator(cls, itr, order_fn: Callable[[_K], _T] = lambda x: x) -> "Generator[Tuple[_T, stream[_K]],None,None]": """ Produce groups of consecutive elements using itertools.groupby. The function order_fn defines the consecutive logic by assigning a position to each element. @@ -642,18 +681,18 @@ def __group_consecutive_generator(cls, itr, order_fn: Callable[[_K], _T] = lambd for _, group in groupby(enumerate(itr), key=key_fn): yield stream(group).map(itemgetter(1)) - def group_consecutive(self, order_fn: Callable[[_K], _T] = lambda x: x) -> 'stream[Tuple[_T, stream[_K]]]': + def group_consecutive(self, order_fn: Callable[[_K], _T] = lambda x: x) -> "stream[Tuple[_T, stream[_K]]]": return stream(self.__group_consecutive_generator(self, order_fn)) @staticmethod - def __stream_on_second_el(t: Tuple[_K, Iterable[_T]]) -> 'Tuple[_K, stream[_T]]': + def __stream_on_second_el(t: Tuple[_K, Iterable[_T]]) -> "Tuple[_K, stream[_T]]": return t[0], stream(t[1]) @staticmethod - def __slist_on_second_el(t: Tuple[_K, Iterable[_T]]) -> 'Tuple[_K, slist[_T]]': + def __slist_on_second_el(t: Tuple[_K, Iterable[_T]]) -> "Tuple[_K, slist[_T]]": return t[0], slist(t[1]) - def groupBySorted(self, keyfunc: Optional[Callable[[_K], _T]] = None) -> 'stream[Tuple[_T, stream[_K]]]': + def groupBySorted(self, keyfunc: Optional[Callable[[_K], _T]] = None) -> "stream[Tuple[_T, stream[_K]]]": """ Make a stream of consecutive keys and groups (as streams) from the self. The iterable needs to already be sorted on the same key function. @@ -662,7 +701,7 @@ def groupBySorted(self, keyfunc: Optional[Callable[[_K], _T]] = None) -> 'stream """ return stream(partial(groupby, iterable=self, key=keyfunc)).map(self.__stream_on_second_el) - def groupBySortedToList(self, keyfunc: Callable[[_K], _T] = _IDENTITY_FUNC) -> 'stream[Tuple[_T, slist[_K]]]': + def groupBySortedToList(self, keyfunc: Callable[[_K], _T] = _IDENTITY_FUNC) -> "stream[Tuple[_T, slist[_K]]]": """ Make a stream of consecutive keys and groups (as streams) from the self. The iterable needs to already be sorted on the same key function. @@ -671,7 +710,7 @@ def groupBySortedToList(self, keyfunc: Callable[[_K], _T] = _IDENTITY_FUNC) -> ' """ return stream(partial(groupby, iterable=self, key=keyfunc)).map(self.__slist_on_second_el) - def countByValue(self) -> 'sdict[_K,int]': + def countByValue(self) -> "sdict[_K,int]": return sdict(collections.Counter(self)) @overload @@ -697,27 +736,26 @@ def reduce(self, f: Callable[[_T, _K], _T], init: _T = None) -> _T: def reduce(self, f, init=None): if init is None: return reduce(f, self) - else: - return reduce(f, self, init) + return reduce(f, self, init) - def transform(self, f: Callable[[Iterable[_K]], Iterable[_V]]) -> 'stream[_V]': + def transform(self, f: Callable[[Iterable[_K]], Iterable[_V]]) -> "stream[_V]": return stream(partial(f, self)) - def shuffle(self, random=None) -> 'slist[_K]': + def shuffle(self, random=None) -> "slist[_K]": lst = self.toList() - shuffle(lst, random=random) + shuffle(lst, random=random) # pylint: disable=deprecated-argument return lst - def toSet(self) -> 'sset[_K]': + def toSet(self) -> "sset[_K]": return sset(self) - def toList(self) -> 'slist[_K]': + def toList(self) -> "slist[_K]": return slist(self) def sorted(self, key=None, reverse=False): return slist(sorted(self, key=key, reverse=reverse)) - def toMap(self: 'stream[Tuple[_T,_V]]') -> 'sdict[_T,_V]': + def toMap(self: "stream[Tuple[_T,_V]]") -> "sdict[_T,_V]": return sdict(self) to_list = toList @@ -725,7 +763,7 @@ def toMap(self: 'stream[Tuple[_T,_V]]') -> 'sdict[_T,_V]': to_map = toMap to_dict = toMap - def toSumCounter(self: 'stream[Tuple[_T,_V]]') -> 'sdict[_T,_V]': + def toSumCounter(self: "stream[Tuple[_T,_V]]") -> "sdict[_T,_V]": """ Elements should be tuples (T, V) where V can be summed :return: sdict on stream elements @@ -740,7 +778,7 @@ def toSumCounter(self: 'stream[Tuple[_T,_V]]') -> 'sdict[_T,_V]': return res @overload - def __getitem__(self, i: slice) -> 'stream[_K]': + def __getitem__(self, i: slice) -> "stream[_K]": ... @overload @@ -750,20 +788,17 @@ def __getitem__(self, i: int) -> _K: def __getitem__(self, i: Union[slice, int]): if isinstance(i, slice): return self.__getslice(i.start, i.stop, i.step) - else: - tk = 0 - while tk < i: - self.next() - tk += 1 - return self.next() - - def __getslice(self, start: Optional[int] = None, - stop: Optional[int] = None, - step: Optional[int] = None) -> 'stream[_K]': + tk = 0 + while tk < i: + self.next() + tk += 1 + return self.next() + + def __getslice(self, start: Optional[int] = None, stop: Optional[int] = None, step: Optional[int] = None) -> "stream[_K]": # ToDo:fix this for cases where self._itr is generator from fastmap(), so have to be closed() return stream(lambda: itertools.islice(self, start, stop, step)) - def __add__(self, other) -> 'stream[_K]': + def __add__(self, other) -> "stream[_K]": if not isinstance(other, (ItrFromFunc, stream)): othItr = stream(lambda: other) else: @@ -776,7 +811,7 @@ def __add__(self, other) -> 'stream[_K]': i = ItrFromFunc(lambda: self._itr) return stream(partial(itertools.chain.from_iterable, (i, othItr))) - def __iadd__(self, other) -> 'stream[_K]': + def __iadd__(self, other) -> "stream[_K]": if not isinstance(other, (ItrFromFunc, stream)): othItr = stream(lambda: other) else: @@ -800,27 +835,26 @@ def size(self) -> int: def join(self, f: Callable[[_K], _V] = None) -> Union[_K, str]: if f is None: - return ''.join(self) - elif isinstance(f, str): + return "".join(self) + if isinstance(f, str): return f.join(self) - else: - itr = iter(self) - r = next(itr) - last = r - while True: - try: - n = next(itr) - r += f(last) - last = n - r += n - except StopIteration: - break - return r + itr = iter(self) + r = next(itr) + last = r + while True: + try: + n = next(itr) + r += f(last) + last = n + r += n + except StopIteration: + break + return r def mkString(self, c) -> str: return self.join(c) - def batch(self, size: int) -> 'stream[slist[_K]]': + def batch(self, size: int) -> "stream[slist[_K]]": """ :param size: size of batch It groups elements of stream into batches of size `size` and returns stream of batches which are slists @@ -838,7 +872,7 @@ def batch_gen(itr): return stream(lambda: stream(batch_gen(iter(self)))) - def take(self, n: int) -> 'stream[_K]': + def take(self, n: int) -> "stream[_K]": def gen(other_gen: GeneratorType, n): count = 0 while count < n: @@ -853,11 +887,9 @@ def gen(other_gen: GeneratorType, n): if isinstance(self._itr, GeneratorType): return stream(gen(self._itr, n)) - else: - return self[:n] + return self[:n] - # ToDo: add tests for takeWhile - def takeWhile(self, predicate: Callable[[_K], bool]) -> 'stream[_K]': + def takeWhile(self, predicate: Callable[[_K], bool]) -> "stream[_K]": def gen(other_gen: Union[GeneratorType, Iterable[_K]], pred: Callable[[_K], bool]): isGen = True if not isinstance(other_gen, GeneratorType): @@ -872,7 +904,8 @@ def gen(other_gen: Union[GeneratorType, Iterable[_K]], pred: Callable[[_K], bool break except StopIteration: break - if isGen: other_gen.close() + if isGen: + other_gen.close() return stream(gen(self, predicate)) @@ -892,7 +925,7 @@ def next(self) -> _K: self._f = None return next(self._itr) - def head(self, n: int) -> 'stream[_K]': + def head(self, n: int) -> "stream[_K]": "Return a stream over the first n items" return stream(itertools.islice(self, n)) @@ -909,26 +942,26 @@ def quantify(self, predicate: Callable[[_K], bool]) -> int: "Count how many times the predicate is true" return sum(self.map(predicate)) - def pad_with(self, pad: Any) -> 'stream[Union[Any,_K]]': + def pad_with(self, pad: Any) -> "stream[Union[Any,_K]]": """Returns the sequence elements and then returns None indefinitely. Useful for emulating the behavior of the built-in map() function. """ return stream(itertools.chain(self, itertools.repeat(pad))) - def roundrobin(self) -> 'stream': + def roundrobin(self) -> "stream": """ roundrobin('ABC', 'D', 'EF') --> A D E B F C Recipe credited to https://docs.python.org/3/library/itertools.html#itertools.chain.from_iterable """ - def gen(s: 'stream'): + def gen(s: "stream"): num_active = s.size() nexts = itertools.cycle(iter(it).__next__ for it in s) while num_active: try: - for next in nexts: - yield next() + for _next in nexts: + yield _next() except StopIteration: # Remove the iterator we just exhausted from the cycle. num_active -= 1 @@ -952,13 +985,12 @@ def min_default(self, default: _T, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> except ValueError as e: if "empty sequence" in e.args[0]: return default - else: - raise + raise def max(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> _V: return max(self, key=key) - def maxes(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> 'slist[_V]': + def maxes(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> "slist[_V]": i = iter(self) aMaxes = slist([next(i)]) mval = key(aMaxes[0]) @@ -971,7 +1003,7 @@ def maxes(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> 'slist[_V]': aMaxes.append(v) return aMaxes - def mins(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> 'slist[_V]': + def mins(self, key: Callable[[_K], _V] = _IDENTITY_FUNC) -> "slist[_V]": i = iter(self) aMaxes = slist([next(i)]) mval = key(aMaxes[0]) @@ -996,11 +1028,11 @@ def pstddev(self) -> float: sm += el n += 1 if n < 1: - raise ValueError('Standard deviation requires at least one data point') + raise ValueError("Standard deviation requires at least one data point") mean = float(sm) / n ss = sum((x - mean) ** 2 for x in self) pvar = ss / n # the population variance - return pvar ** 0.5 + return pvar**0.5 def mean(self) -> float: """Return the sample arithmetic mean of data. in one single pass""" @@ -1010,13 +1042,13 @@ def mean(self) -> float: sm += el n += 1 if n < 1: - raise ValueError('Mean requires at least one data point') + raise ValueError("Mean requires at least one data point") return sm / float(n) - def zip(self) -> 'stream[_V]': + def zip(self) -> "stream[_V]": return stream(zip(*(self.toList()))) - def distinct(self, key: Optional[Callable[[_K], _V]] = None) -> 'stream[_K]': + def distinct(self, key: Optional[Callable[[_K], _V]] = None) -> "stream[_K]": """ The stream items should be hashable and comparable. :param key: optional, maps the elements to comparable objects @@ -1027,23 +1059,27 @@ def distinct(self, key: Optional[Callable[[_K], _V]] = None) -> 'stream[_K]': unique = distinct - def tqdm(self, desc: Optional[str] = None, - total: Optional[int] = None, - leave: bool = True, - file: Optional[io.TextIOWrapper] = None, - ncols: Optional[int] = None, - mininterval: float = 0.1, - maxinterval: float = 10.0, - ascii: Optional[Union[str, bool]] = None, - unit: str = 'it', - unit_scale: Optional[Union[bool, int, float]] = False, - dynamic_ncols: Optional[bool] = False, - smoothing: Optional[float] = 0.3, - initial: int = 0, - position: Optional[int] = None, - postfix: Optional[dict] = None, - gui: bool = False, - **kwargs) -> 'stream[_K]': + # pylint: disable=too-many-arguments + def tqdm( + self, + desc: Optional[str] = None, + total: Optional[int] = None, + leave: bool = True, + file: Optional[io.TextIOWrapper] = None, + ncols: Optional[int] = None, + mininterval: float = 0.1, + maxinterval: float = 10.0, + ascii: Optional[Union[str, bool]] = None, # pylint: disable=redefined-builtin + unit: str = "it", + unit_scale: Optional[Union[bool, int, float]] = False, + dynamic_ncols: Optional[bool] = False, + smoothing: Optional[float] = 0.3, + initial: int = 0, + position: Optional[int] = None, + postfix: Optional[dict] = None, + gui: bool = False, + **kwargs, + ) -> "stream[_K]": """ :param desc: Prefix for the progressbar. :param total: The number of expected iterations. If unspecified, @@ -1094,14 +1130,30 @@ def tqdm(self, desc: Optional[str] = None, :param kwargs: Params to be sent to tqdm() :return: self stream """ - return stream(tqdm(iterable=self, desc=desc, total=total, leave=leave, - file=file, ncols=ncols, mininterval=mininterval, maxinterval=maxinterval, - ascii=ascii, unit=unit, unit_scale=unit_scale, dynamic_ncols=dynamic_ncols, - smoothing=smoothing, - initial=initial, position=position, postfix=postfix, - gui=gui, **kwargs)) - - def throttle(self, max_req: int, interval: float) -> 'stream[_K]': + return stream( + tqdm( + iterable=self, + desc=desc, + total=total, + leave=leave, + file=file, + ncols=ncols, + mininterval=mininterval, + maxinterval=maxinterval, + ascii=ascii, + unit=unit, + unit_scale=unit_scale, + dynamic_ncols=dynamic_ncols, + smoothing=smoothing, + initial=initial, + position=position, + postfix=postfix, + gui=gui, + **kwargs, + ) + ) + + def throttle(self, max_req: int, interval: float) -> "stream[_K]": """ :param max_req: number of requests :param interval: period in number of seconds @@ -1124,28 +1176,27 @@ def binaryToChunk(binaryData: bytes) -> bytes: return p + binaryData def dumpToPickle(self, fileStream): - ''' + """ :param fileStream: should be binary output stream :type fileStream: file :return: Nothing - ''' + """ - for el in self.map(lambda _: pickle.dumps(_, pickle.HIGHEST_PROTOCOL, fix_imports=True)).map( - stream.binaryToChunk): + for el in self.map(lambda _: pickle.dumps(_, pickle.HIGHEST_PROTOCOL, fix_imports=True)).map(stream.binaryToChunk): fileStream.write(el) def dumpPickledToWriter(self, writer: Callable[[bytes], _T]) -> None: - ''' + """ :param writer: should be binary output callable stream - ''' + """ for el in self: - writer(stream._picklePack(el)) + writer(stream._picklePack(el)) # pylint: disable=protected-access @staticmethod def _picklePack(el) -> bytes: return stream.binaryToChunk(pickle.dumps(el, pickle.HIGHEST_PROTOCOL)) - def exceptIndexes(self, *indexes: List[int]) -> 'stream[_K]': + def exceptIndexes(self, *indexes: List[int]) -> "stream[_K]": """ Doesn't support negative indexes as the stream doesn't have a length :return: the stream with filtered out elements on positions @@ -1170,7 +1221,7 @@ def __get_validators__(cls): @classmethod def _pydantic_validator(cls, v): if not isinstance(v, cls): - raise TypeError(f'{repr(v)} is of type {type(v)} but is expected to be of {cls}') + raise TypeError(f"{repr(v)} is of type {type(v)} but is expected to be of {cls}") return v @@ -1184,20 +1235,17 @@ def __iter__(self) -> Iterator[_K]: def __get_itr(self): if self._itr is not None: return self._itr - else: - return self._f() + return self._f() def __repr__(self): if isinstance(self._itr, list): - repr(self._itr) - else: - return object.__repr__(self) + return repr(self._itr) + return object.__repr__(self) def __str__(self): if isinstance(self._itr, list): return str(self._itr) - else: - return object.__str__(self) + return object.__str__(self) def __reversed__(self): try: @@ -1207,6 +1255,7 @@ def __reversed__(self): @staticmethod def __binaryChunksStreamGenerator(fs, format=" 'stream[_V]': + def readFromBinaryChunkStream(readStream: BinaryIO, format: str = " "stream[_V]": """ :param statHandler: statistics handler, will be called before every yield with a tuple (n,size) """ return stream(stream.__binaryChunksStreamGenerator(readStream, format, statHandler)) @staticmethod - def loadFromPickled(file: BinaryIO, format: str = " 'stream[_V]': + def loadFromPickled(file: BinaryIO, format: str = " "stream[_V]": """ :param file: should be path or binary file stream :param format: format of the header @@ -1293,9 +1341,9 @@ def __repr__(self): class buffered_stream(AbstractSynchronizedBufferedStream): - def __init__(self, buffers: 'Iterable[Iterable[_T]]'): + def __init__(self, buffers: "Iterable[Iterable[_T]]"): self.__buffers = iter(buffers) - super(buffered_stream, self).__init__() + super().__init__() def _getNextBuffer(self) -> Iterable[_T]: try: @@ -1316,37 +1364,37 @@ def __iter__(self): return set.__iter__(self) # Below methods enable chaining and lambda using - def update(self, *args, **kwargs) -> 'sset[_K]': + def update(self, *args, **kwargs) -> "sset[_K]": # ToDo: Add option to update with iterables, as set.update supports only other set set.update(self, *args, **kwargs) return self - def intersection_update(self, *args, **kwargs) -> 'sset[_K]': + def intersection_update(self, *args, **kwargs) -> "sset[_K]": set.intersection_update(self, *args, **kwargs) return self - def difference_update(self, *args, **kwargs) -> 'sset[_K]': + def difference_update(self, *args, **kwargs) -> "sset[_K]": set.difference_update(self, *args, **kwargs) return self - def symmetric_difference_update(self, *args, **kwargs) -> 'sset[_K]': - super(sset, self).symmetric_difference_update(*args, **kwargs) + def symmetric_difference_update(self, *args, **kwargs) -> "sset[_K]": + super().symmetric_difference_update(*args, **kwargs) return self - def clear(self, *args, **kwargs) -> 'sset[_K]': + def clear(self, *args, **kwargs) -> "sset[_K]": set.clear(self, *args, **kwargs) return self - def remove(self, *args, **kwargs) -> 'sset[_K]': - super(sset, self).remove(*args, **kwargs) + def remove(self, *args, **kwargs) -> "sset[_K]": + super().remove(*args, **kwargs) return self - def add(self, *args, **kwargs) -> 'sset[_K]': - super(sset, self).add(*args, **kwargs) + def add(self, *args, **kwargs) -> "sset[_K]": + super().add(*args, **kwargs) return self - def discard(self, *args, **kwargs) -> 'sset[_K]': - super(sset, self).discard(*args, **kwargs) + def discard(self, *args, **kwargs) -> "sset[_K]": + super().discard(*args, **kwargs) return self def __reversed__(self): @@ -1358,16 +1406,48 @@ def __or__(self, s: AbstractSet[_V]) -> Set[Union[_K, _V]]: def union(self, *s: Iterable[_K]) -> Set[_K]: return sset(super().union(*s)) - def tqdm(self, desc: Optional[str] = None, total: Optional[int] = None, leave: bool = True, - file: Optional[io.TextIOWrapper] = None, ncols: Optional[int] = None, mininterval: float = 0.1, - maxinterval: float = 10.0, ascii: Optional[Union[str, bool]] = None, unit: str = 'it', - unit_scale: Optional[Union[bool, int, float]] = False, dynamic_ncols: Optional[bool] = False, - smoothing: Optional[float] = 0.3, initial: int = 0, position: Optional[int] = None, - postfix: Optional[dict] = None, gui: bool = False, **kwargs) -> 'stream[_K]': + # pylint: disable=too-many-arguments + def tqdm( + self, + desc: Optional[str] = None, + total: Optional[int] = None, + leave: bool = True, + file: Optional[io.TextIOWrapper] = None, + ncols: Optional[int] = None, + mininterval: float = 0.1, + maxinterval: float = 10.0, + ascii: Optional[Union[str, bool]] = None, # pylint: disable=redefined-builtin + unit: str = "it", + unit_scale: Optional[Union[bool, int, float]] = False, + dynamic_ncols: Optional[bool] = False, + smoothing: Optional[float] = 0.3, + initial: int = 0, + position: Optional[int] = None, + postfix: Optional[dict] = None, + gui: bool = False, + **kwargs, + ) -> "stream[_K]": if total is None: total = self.size() - return super().tqdm(desc, total, leave, file, ncols, mininterval, maxinterval, ascii, unit, unit_scale, - dynamic_ncols, smoothing, initial, position, postfix, gui, **kwargs) + return super().tqdm( + desc, + total, + leave, + file, + ncols, + mininterval, + maxinterval, + ascii, + unit, + unit_scale, + dynamic_ncols, + smoothing, + initial, + position, + postfix, + gui, + **kwargs, + ) def __and__(self, other): return sset(super().__and__(other)) @@ -1396,29 +1476,28 @@ def _itr(self): def __init__(self, *args, **kwrds): list.__init__(self, *args, **kwrds) - def __getitem__(self, item) -> 'Union[_K,slist[_K]]': + def __getitem__(self, item) -> "Union[_K,slist[_K]]": if isinstance(item, slice): return slist(list.__getitem__(self, item)) - else: - return list.__getitem__(self, item) + return list.__getitem__(self, item) - def extend(self, iterable: Iterable[_K]) -> 'slist[_K]': + def extend(self, iterable: Iterable[_K]) -> "slist[_K]": list.extend(self, iterable) return self - def append(self, x) -> 'slist[_K]': + def append(self, x) -> "slist[_K]": list.append(self, x) return self - def remove(self, x) -> 'slist[_K]': + def remove(self, x) -> "slist[_K]": list.remove(self, x) return self - def insert(self, i, x) -> 'slist[_K]': + def insert(self, i, x) -> "slist[_K]": list.insert(self, i, x) return self - def exceptIndexes(self, *indexes: List[int]) -> 'stream[_K]': + def exceptIndexes(self, *indexes: List[int]) -> "stream[_K]": """ Supports negative indexes :type indexes: list[int] @@ -1426,7 +1505,7 @@ def exceptIndexes(self, *indexes: List[int]) -> 'stream[_K]': :rtype: stream [ T ] """ - def indexIgnorer(indexSet: frozenset, _stream: 'stream[_K]'): + def indexIgnorer(indexSet: frozenset, _stream: "stream[_K]"): i = 0 for el in _stream: if i not in indexSet: @@ -1437,7 +1516,7 @@ def indexIgnorer(indexSet: frozenset, _stream: 'stream[_K]'): indexSet = frozenset(stream(indexes).map(lambda i: i if i >= 0 else i + sz)) return stream(lambda: indexIgnorer(indexSet, self)) - def __iadd__(self, other) -> 'stream[_K]': + def __iadd__(self, other) -> "stream[_K]": list.__iadd__(self, other) return self @@ -1446,16 +1525,48 @@ def __add__(self, x: List[_K]) -> Union[stream[_K], List[_K]]: return stream(self) + x return slist(super().__add__(x)) - def tqdm(self, desc: Optional[str] = None, total: Optional[int] = None, leave: bool = True, - file: Optional[io.TextIOWrapper] = None, ncols: Optional[int] = None, mininterval: float = 0.1, - maxinterval: float = 10.0, ascii: Optional[Union[str, bool]] = None, unit: str = 'it', - unit_scale: Optional[Union[bool, int, float]] = False, dynamic_ncols: Optional[bool] = False, - smoothing: Optional[float] = 0.3, initial: int = 0, position: Optional[int] = None, - postfix: Optional[dict] = None, gui: bool = False, **kwargs) -> 'stream[_K]': + # pylint: disable=too-many-arguments + def tqdm( + self, + desc: Optional[str] = None, + total: Optional[int] = None, + leave: bool = True, + file: Optional[io.TextIOWrapper] = None, + ncols: Optional[int] = None, + mininterval: float = 0.1, + maxinterval: float = 10.0, + ascii: Optional[Union[str, bool]] = None, # pylint: disable=redefined-builtin + unit: str = "it", + unit_scale: Optional[Union[bool, int, float]] = False, + dynamic_ncols: Optional[bool] = False, + smoothing: Optional[float] = 0.3, + initial: int = 0, + position: Optional[int] = None, + postfix: Optional[dict] = None, + gui: bool = False, + **kwargs, + ) -> "stream[_K]": if total is None: total = self.size() - return super().tqdm(desc, total, leave, file, ncols, mininterval, maxinterval, ascii, unit, unit_scale, - dynamic_ncols, smoothing, initial, position, postfix, gui, **kwargs) + return super().tqdm( + desc, + total, + leave, + file, + ncols, + mininterval, + maxinterval, + ascii, + unit, + unit_scale, + dynamic_ncols, + smoothing, + initial, + position, + postfix, + gui, + **kwargs, + ) class sdict(Dict[_K, _V], dict, _IStream): @@ -1481,23 +1592,55 @@ def values(self) -> stream[_V]: def items(self) -> stream[Tuple[_K, _V]]: return stream(dict.items(self)) - def update(self, other=None, **kwargs) -> 'sdict[_K,_V]': + def update(self, other=None, **kwargs) -> "sdict[_K,_V]": dict.update(self, other, **kwargs) return self - def copy(self) -> 'sdict[_K,_V]': + def copy(self) -> "sdict[_K,_V]": return sdict(self.items()) - def tqdm(self, desc: Optional[str] = None, total: Optional[int] = None, leave: bool = True, - file: Optional[io.TextIOWrapper] = None, ncols: Optional[int] = None, mininterval: float = 0.1, - maxinterval: float = 10.0, ascii: Optional[Union[str, bool]] = None, unit: str = 'it', - unit_scale: Optional[Union[bool, int, float]] = False, dynamic_ncols: Optional[bool] = False, - smoothing: Optional[float] = 0.3, initial: int = 0, position: Optional[int] = None, - postfix: Optional[dict] = None, gui: bool = False, **kwargs) -> 'stream[_K]': + # pylint: disable=too-many-arguments + def tqdm( + self, + desc: Optional[str] = None, + total: Optional[int] = None, + leave: bool = True, + file: Optional[io.TextIOWrapper] = None, + ncols: Optional[int] = None, + mininterval: float = 0.1, + maxinterval: float = 10.0, + ascii: Optional[Union[str, bool]] = None, # pylint: disable=redefined-builtin + unit: str = "it", + unit_scale: Optional[Union[bool, int, float]] = False, + dynamic_ncols: Optional[bool] = False, + smoothing: Optional[float] = 0.3, + initial: int = 0, + position: Optional[int] = None, + postfix: Optional[dict] = None, + gui: bool = False, + **kwargs, + ) -> "stream[_K]": if total is None: total = self.size() - return super().tqdm(desc, total, leave, file, ncols, mininterval, maxinterval, ascii, unit, unit_scale, - dynamic_ncols, smoothing, initial, position, postfix, gui, **kwargs) + return super().tqdm( + desc, + total, + leave, + file, + ncols, + mininterval, + maxinterval, + ascii, + unit, + unit_scale, + dynamic_ncols, + smoothing, + initial, + position, + postfix, + gui, + **kwargs, + ) class defaultstreamdict(sdict): @@ -1505,25 +1648,23 @@ class defaultstreamdict(sdict): def _itr(self): return ItrFromFunc(lambda: iter(self)) + # pylint: disable=keyword-arg-before-vararg def __init__(self, default_factory=None, *a, **kw): - if (default_factory is not None and - not callable(default_factory)): - raise TypeError('first argument must be callable') - super(self.__class__, self).__init__(*a, **kw) + if default_factory is not None and not callable(default_factory): + raise TypeError("first argument must be callable") + super().__init__(*a, **kw) if default_factory is None: - self.__default_factory = lambda: object() + self.__default_factory = object else: self.__default_factory = default_factory def __getitem__(self, key: _K) -> _V: try: - return super(self.__class__, self).__getitem__(key) + return super().__getitem__(key) except KeyError: return self.__missing__(key) def __missing__(self, key): - # if self.__default_factory is None: - # raise KeyError(key) self[key] = value = self.__default_factory() return value @@ -1536,19 +1677,16 @@ def __reduce__(self): return type(self), args, None, None, iter(itms) def copy(self) -> Mapping[_K, _V]: - return self.__copy__() + return self.__copy__() # pylint: disable=unnecessary-dunder-call def __copy__(self): return type(self)(self.__default_factory, self) def __deepcopy__(self, memo): - import copy - return type(self)(self.__default_factory, - copy.deepcopy(list(self.items()))) + return type(self)(self.__default_factory, copy.deepcopy(list(self.items()))) def __repr__(self) -> str: - return 'defaultdict(%s, %s)' % (self.__default_factory, - super(self.__class__, self).__repr__()) + return f"defaultdict({self.__default_factory!s}, {super(self.__class__, self)!r})" def __str__(self) -> str: return dict.__str__(self) @@ -1563,7 +1701,7 @@ def sfilter(f, itr: Iterable[_K]) -> stream[_K]: def iter_except(func: Callable[[], _K], exc: Exception, first: Optional[Callable[[], _K]] = None) -> _K: - """ Call a function repeatedly until an exception is raised. + """Call a function repeatedly until an exception is raised. Converts a call-until-exception interface to an iterator interface. Like builtins.iter(func, sentinel) but uses an exception instead diff --git a/streamerate/tests/test_Streams.py b/streamerate/tests/test_Streams.py index 106574d..e79954d 100644 --- a/streamerate/tests/test_Streams.py +++ b/streamerate/tests/test_Streams.py @@ -12,15 +12,23 @@ from multiprocessing import Pool from unittest.mock import MagicMock -from pydantic import validate_arguments, ValidationError -from pyxtension.Json import JsonList, Json - -from streamerate.streams import defaultstreamdict, sdict, slist, sset, stream, TqdmMapper +import eventlet +from pydantic import ValidationError, validate_arguments +from pyxtension.Json import Json, JsonList + +from streamerate.streams import ( + TqdmMapper, + defaultstreamdict, + sdict, + slist, + sset, + stream, +) ifilter = filter xrange = range -__author__ = 'andrei.suiu@gmail.com' +__author__ = "andrei.suiu@gmail.com" def PICKABLE_DUMB_FUNCTION(x): @@ -51,7 +59,7 @@ def __init__(self, message): self.message = message def __str__(self): # pragma: no cover - return 'APIError(code=%s)' % (self.message) + return "APIError(code=%s)" % (self.message) def PICKABLE_FUNCTION_RAISES(x): @@ -62,7 +70,6 @@ class SlistTestCase(unittest.TestCase): def test_slist_str_nominal(self): l = [1, 2, 3] s = slist(l) - s1 = str(s) self.assertEqual(str(s), str(l)) def test_slist_repr_nominal(self): @@ -73,7 +80,7 @@ def test_slist_repr_nominal(self): def test_slist_add_list(self): l1 = slist([1, 2]) l2 = slist([3, 4]) - l3 = (l1 + l2) + l3 = l1 + l2 self.assertIsInstance(l3, stream) self.assertIsInstance(l3, slist) self.assertListEqual(l3.toList(), [1, 2, 3, 4]) @@ -81,7 +88,7 @@ def test_slist_add_list(self): def test_slist_add_stream(self): l1 = slist([1, 2]) l2 = stream([3, 4]) - l3 = (l1 + l2) + l3 = l1 + l2 self.assertIsInstance(l3, stream) self.assertNotIsInstance(l3, slist) self.assertListEqual(l3.toList(), [1, 2, 3, 4]) @@ -104,11 +111,12 @@ def test_reversedNominal(self): class SdictTestCase(unittest.TestCase): + @unittest.skip("Json lib depends on streamerate, so it would generate recursive imports") def testSdictToJson(self): j = stream((("a", 2), (3, 4))).toMap().toJson() self.assertIsInstance(j, Json) self.assertEqual(j.a, 2) - self.assertDictEqual(j, {'a': 2, 3: 4}) + self.assertDictEqual(j, {"a": 2, 3: 4}) def test_sdict(self): d = sdict({1: 2, 3: 4}) @@ -144,8 +152,19 @@ def test_sset_intersection_updateReturnsSelf(self): self.assertEqual(sset((1, 2)).update(set((2, 3))), set((1, 2, 3))) def test_ssetChaining(self): - s = sset().add(0).clear().add(1).add(2).remove(2).discard(3).update(set((3, 4, 5))) \ - .intersection_update(set((1, 3, 4))).difference_update(set((4,))).symmetric_difference_update(set((3, 4))) + s = ( + sset() + .add(0) + .clear() + .add(1) + .add(2) + .remove(2) + .discard(3) + .update(set((3, 4, 5))) + .intersection_update(set((1, 3, 4))) + .difference_update(set((4,))) + .symmetric_difference_update(set((3, 4))) + ) self.assertEqual(s, set((1, 4))) def test_reversed_raises(self): @@ -203,7 +222,12 @@ def test_difference(self): s2_2 = sset({1, 2, 5}) s3 = s1.difference(s2, s2_2) self.assertIsInstance(s3, sset) - self.assertSetEqual(s3, {3, }) + self.assertSetEqual( + s3, + { + 3, + }, + ) def test_symmetric_difference(self): s1 = sset({1, 2, 3}) @@ -213,382 +237,216 @@ def test_symmetric_difference(self): self.assertSetEqual(s3, {3, 4}) -class StreamTestCase(unittest.TestCase): +class DefaultStreamDictTestCase(unittest.TestCase): + def test_defaultstreamdictBasics(self): + dd = defaultstreamdict(slist) + dd[1].append(2) + self.assertEqual(dd, {1: [2]}) - @classmethod - def setUpClass(cls) -> None: - cls.N_processes = 10 - cls.pool = Pool(cls.N_processes) + def test_defaultstreamdictSerialization(self): + dd = defaultstreamdict(slist) + dd[1].append(2) + s = pickle.dumps(dd) + newDd = pickle.loads(s) + self.assertEqual(newDd, dd) + self.assertIsInstance(newDd[1], slist) - def setUp(self): - self.s = lambda: stream((1, 2, 3)) - def test_fastFlatMap_reiteration(self): - l = stream(lambda: (xrange(i) for i in xrange(5))).fastFlatMap() - self.assertListEqual(sorted(l.toList()), sorted([0, 0, 1, 0, 1, 2, 0, 1, 2, 3])) - self.assertEqual(sorted(l.toList()), - sorted([0, 0, 1, 0, 1, 2, 0, 1, 2, 3])) # second time to assert the regeneration of generator +class fastmapTestCase(unittest.TestCase): + def test_fastmap_nominal(self): + s = stream(xrange(100)) + res = s.fastmap(lambda x: x * x, poolSize=4).toSet() + expected = set(i * i for i in xrange(100)) + self.assertSetEqual(res, expected) + + def test_fastmap_time(self): + def sleepFunc(el): + time.sleep(0.3) + return el * el + + s = stream(xrange(100)) + t1 = time.time() + res = s.fastmap(sleepFunc, poolSize=50).toSet() + dt = time.time() - t1 + expected = set(i * i for i in xrange(100)) + self.assertSetEqual(res, expected) + self.assertLessEqual(dt, 1.5) def test_fastmap_reiteration(self): l = stream(lambda: (xrange(i) for i in xrange(5))).fastmap(len) self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) # second time to assert the regeneration of generator - def testStream(self): - s = self.s - self.assertEqual(list(ifilter(lambda i: i % 2 == 0, s())), [2]) - self.assertEqual(list(s().filter(lambda i: i % 2 == 0)), [2]) - self.assertEqual(s().filter(lambda i: i % 2 == 0).toList(), [2]) - self.assertEqual(s()[1], 2) - self.assertEqual(s()[1:].toList(), [2, 3]) - self.assertEqual(s().take(2).toList(), [1, 2]) - self.assertAlmostEqual(stream((0, 1, 2, 3)).filter(lambda x: x > 0).entropy(), 1.4591479) - self.assertEqual(stream([(1, 2), (3, 4)]).zip().toList(), [(1, 3), (2, 4)]) - - def test_filterFromGeneratorReinstantiatesProperly(self): - s = stream(lambda: (i for i in xrange(5))) - s = s.filter(lambda e: e % 2 == 0) - self.assertEqual(s.toList(), [0, 2, 4]) - self.assertEqual(s.toList(), [0, 2, 4]) - s = stream(xrange(5)).filter(lambda e: e % 2 == 0) - self.assertEqual(s.toList(), [0, 2, 4]) - self.assertEqual(s.toList(), [0, 2, 4]) - - def test_starfilter(self): - s = stream([(2, 5), (3, 2), (10, 3)]).starfilter(lambda x, y: x > y) - self.assertEqual(s.toList(), [(3, 2), (10, 3)]) - self.assertEqual(s.toList(), [(3, 2), (10, 3)]) + def test_fastmap_one_el(self): + s = stream( + [ + 1, + ] + ) + res = s.fastmap(lambda x: x * x, poolSize=4).toSet() + expected = set((1,)) + self.assertSetEqual(res, expected) - def test_streamExists(self): - s = stream([0, 1]) - self.assertEqual(s.exists(lambda e: e == 0), True) - self.assertEqual(s.exists(lambda e: e == 2), False) + def test_fastmap_no_el(self): + s = stream([]) + res = s.fastmap(lambda x: x * x, poolSize=4).toSet() + expected = set() + self.assertSetEqual(res, expected) - def test_stream_str_doesntChangeStream(self): - s = stream(iter((1, 2, 3, 4))) - str(s) - self.assertListEqual(s.toList(), [1, 2, 3, 4]) + def test_fastmap_None_el(self): + s = stream([None]) + res = s.fastmap(lambda x: x, poolSize=4).toSet() + expected = set([None]) + self.assertSetEqual(res, expected) - def test_stream_repr_doesntChangeStream(self): - s = stream(iter((1, 2, 3, 4))) - repr(s) - self.assertListEqual(s.toList(), [1, 2, 3, 4]) + def test_fastmap_take_less(self): + arr = [] - def testStreamToJson(self): - j = stream((("a", 2), (3, 4))).toJson() - self.assertIsInstance(j, JsonList) - self.assertListEqual(j, [["a", 2], [3, 4]]) + def m(i): + arr.append(i) + return i - def testStreamsFromGenerator(self): - sg = stream(lambda: (i for i in range(4))) - self.assertEqual(sg.size(), 4) - self.assertEqual(sg.size(), 4) - self.assertEqual(sg.filter(lambda x: x > 1).toList(), [2, 3]) - self.assertEqual(sg.filter(lambda x: x > 1).toList(), [2, 3]) - self.assertEqual(sg.map(lambda x: x > 1).toList(), [False, False, True, True]) - self.assertEqual(sg.map(lambda x: x > 1).toList(), [False, False, True, True]) - self.assertEqual(sg.map(lambda i: i ** 2).enumerate().toList(), [(0, 0), (1, 1), (2, 4), (3, 9)]) - self.assertEqual(sg.reduce(lambda x, y: x + y, 5), 11) - self.assertListEqual(list(sg.batch(2)), [[0, 1], [2, 3]]) - self.assertListEqual(list(sg.batch(2)), [[0, 1], [2, 3]]) + s = stream(range(100)).map(m).fastmap(lambda x: x, poolSize=4, bufferSize=5).take(20) + res = s.toList() + self.assertLessEqual(len(arr), 30) + self.assertEqual(len(res), 20) - def test_next_from_gen(self): - # Next consumes from stream - sg = stream(lambda: (i for i in range(4))) - self.assertEqual(sg.next(), 0) - self.assertEqual(sg.next(), 1) - self.assertListEqual(list(sg), [2, 3]) + def test_fastmap_raises_exception(self): + s = stream([None]) + with self.assertRaises(TypeError): + _ = s.fastmap(lambda x: x * x, poolSize=4).toSet() - def test_next_from_list(self): - # Next consumes from stream - sg = stream([i for i in range(4)]) - self.assertEqual(sg.next(), 0) - self.assertEqual(sg.next(), 1) - self.assertListEqual(list(sg), [2, 3]) + def test_traceback_right_when_fastmap_raises_builtin_exception(self): + s = stream([None]) - def testStreamPickling(self): - sio = BytesIO() - expected = slist(slist((i,)) for i in xrange(10)) - expected.dumpToPickle(sio) - sio = BytesIO(sio.getvalue()) + def f(x): + return x * x - result = stream.loadFromPickled(sio) - self.assertListEqual(expected, list(result)) + try: + s.fastmap(f, poolSize=4).toSet() + except TypeError as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, "return x * x") + return + self.fail("No expected exceptions has been raised") - def test_StreamFileReading(self): - sio = BytesIO() - expected = slist(slist((i,)) for i in xrange(10)) - expected.dumpToPickle(sio) - sio = BytesIO(sio.getvalue()) + def test_traceback_right_when_fastmap_raises_custom_exception(self): + class SomeCustomException(Exception): + def __init__(self, message): + self.message = message - result = stream.loadFromPickled(sio) - self.assertEqual(list(expected), list(result)) + def __str__(self): # pragma: no cover + return "APIError(code=%s)" % (self.message) - def test_starmap(self): - s = stream([(2, 5), (3, 2), (10, 3)]).starmap(pow) - self.assertListEqual(s.toList(), [32, 9, 1000]) - self.assertListEqual(s.toList(), [32, 9, 1000]) + s = stream([None]) - def test_faststarmap(self): - s = stream([(2, 5), (3, 2), (10, 3)]).faststarmap(pow) - self.assertSetEqual(s.toSet(), {32, 9, 1000}) - self.assertSetEqual(s.toSet(), {32, 9, 1000}) + def f(x): + raise SomeCustomException("") - def test_mpstarmap(self): - s = stream([(2, 5), (3, 2), (10, 3)]).mpstarmap(pow) - self.assertListEqual(s.toList(), [32, 9, 1000]) - # ToDo: Why does the next fails? - # self.assertListEqual(s.toList(), [32, 9, 1000]) + try: + s.fastmap(f, poolSize=4).toSet() + except SomeCustomException as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, 'raise SomeCustomException("")') + return + self.fail("No expected exceptions has been raised") - def test_mtstarmap(self): - s = stream([(2, 5), (3, 2), (10, 3)]).mtstarmap(pow) - self.assertListEqual(s.toList(), [32, 9, 1000]) - self.assertListEqual(s.toList(), [32, 9, 1000]) - def test_mpfaststarmap(self): - s = stream([(2, 5), (3, 2), (10, 3)]).mpfaststarmap(pow) - self.assertSetEqual(s.toSet(), {32, 9, 1000}) +class gtmapTestCase(unittest.TestCase): + def test_gtmap_nominal(self): + s = stream(xrange(100)) + res = s.gtmap(_rnd_sleep, poolSize=8).toList() + expected = [i * i for i in xrange(100)] + self.assertListEqual(res, expected) - # ToDo: Why does the next fails? - # self.assertSetEqual(s.toSet(), {32, 9, 1000}) + def test_gtmap_time(self): + def sleepFunc(el): + eventlet.sleep(0.3) + return el * el - def test_flatMap_nominal(self): - s = stream([[1, 2], [3, 4], [4, 5]]) - self.assertListEqual(s.flatMap().toList(), [1, 2, 3, 4, 4, 5]) + s = stream(xrange(100)) + t1 = time.time() + res = s.gtmap(sleepFunc, poolSize=50).toSet() + dt = time.time() - t1 + expected = set(i * i for i in xrange(100)) + self.assertSetEqual(res, expected) + self.assertLessEqual(dt, 1.5) - def test_flatMap_withPredicate(self): - s = stream(({1: 2, 3: 4}, {5: 6, 7: 8})) - self.assertEqual(s.flatMap(dict.items).toSet(), set(((1, 2), (5, 6), (3, 4), (7, 8)))) + def test_gtmap_reiteration(self): + l = stream(lambda: (xrange(i) for i in xrange(5))).gtmap(len) + self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) + self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) - def test_flatMap_reiteration(self): - l = stream(lambda: (xrange(i) for i in xrange(5))).flatMap() - self.assertEqual(l.toList(), [0, 0, 1, 0, 1, 2, 0, 1, 2, 3]) - self.assertEqual(l.toList(), - [0, 0, 1, 0, 1, 2, 0, 1, 2, 3]) # second time to assert the regeneration of generator + def test_gtmap_one_el(self): + s = stream( + [ + 1, + ] + ) + res = s.gtmap(lambda x: x * x, poolSize=4).toList() + expected = [1] + self.assertListEqual(res, expected) - def test_flatMap_defaultIdentityFunction(self): - l = slist(({1: 2, 3: 4}, {5: 6, 7: 8})) - self.assertEqual(l.flatMap().toSet(), set((1, 3, 5, 7))) + def test_gtmap_no_el(self): + s = stream([]) + res = s.gtmap(lambda x: x * x, poolSize=4).toList() + expected = [] + self.assertListEqual(res, expected) - def test_reduceUsesInitProperly(self): - self.assertEqual(slist([sset((1, 2)), sset((3, 4))]).reduce(lambda x, y: x.update(y)), set((1, 2, 3, 4))) - self.assertEqual(slist([sset((1, 2)), sset((3, 4))]).reduce(lambda x, y: x.update(y), sset()), - set((1, 2, 3, 4))) + def test_gtmap_None_el(self): + s = stream([None]) + res = s.gtmap(lambda x: x, poolSize=4).toList() + expected = [None] + self.assertListEqual(res, expected) - def test_transform_nominal(self): - s = stream(range(4)) + def test_gtmap_take_less(self): + arr = [] - def f(itr): - for i in itr: - for j in range(i): - yield i + def m(i): + arr.append(i) + return i - self.assertListEqual(s.transform(f).toList(), [1, 2, 2, 3, 3, 3]) + s = stream(range(100)).map(m).gtmap(lambda x: x, poolSize=10).take(20) + res = s.toList() + self.assertLessEqual(len(arr), 30) + self.assertEqual(len(res), 20) - def test_shuffle_nominal(self): - l = list(range(100)) - s = stream(l).shuffle() - self.assertNotEqual(l, list(s)) - self.assertSetEqual(set(l), s.toSet()) + def test_gtmap_raises_exception(self): + s = stream([None]) + with self.assertRaises(TypeError): + res = s.gtmap(lambda x: x * x, poolSize=4).toSet() - def test_maxes(self): - self.assertEqual(stream(['a', 'abc', 'abcd', 'defg', 'cde']).maxes(lambda s: len(s)), ['abcd', 'defg']) + def test_traceback_right_when_gtmap_raises_custom_exception(self): + s = stream([None]) + try: + s.gtmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() + except SomeCustomException as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, 'raise SomeCustomException("")') + return + self.fail("No expected exceptions has been raised") - def test_mins(self): - self.assertEqual(stream(['abc', 'a', 'abcd', 'defg', 'cde']).mins(lambda s: len(s)), ['a']) + def test_traceback_right_when_gtmap_raises_builtin_exception(self): + s = stream([None]) - def test_min_nominal(self): - self.assertEqual(stream([2, 1]).min(), 1) - self.assertEqual(stream(['abc', 'a']).min(key=len), 'a') + def f(x): + return x * x - def test_min_raises_on_empty_sequence(self): - with self.assertRaises(ValueError): - stream().min() - - def test_min_default_nominal(self): - self.assertEqual(stream([2, 1]).min_default('default'), 1) - self.assertEqual(stream(['abc', 'a']).min_default('default', key=len), 'a') - self.assertEqual(stream().min_default('default'), 'default') - - def test_defaultstreamdictBasics(self): - dd = defaultstreamdict(slist) - dd[1].append(2) - self.assertEqual(dd, {1: [2]}) - - def test_defaultstreamdictSerialization(self): - dd = defaultstreamdict(slist) - dd[1].append(2) - s = pickle.dumps(dd) - newDd = pickle.loads(s) - self.assertEqual(newDd, dd) - self.assertIsInstance(newDd[1], slist) - - def test_stream_add(self): - s1 = stream([1, 2]) - s2 = stream([3, 4]) - s3 = s1 + s2 - ll = s3.toList() - self.assertEqual(s3.toList(), [1, 2, 3, 4]) - self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - s1 = s1 + s2 - self.assertEqual(s1.toList(), [1, 2, 3, 4]) - self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - - def test_stream_add_nonstream(self): - s1 = stream([1, 2]) - s2 = range(3, 5) - s3 = s1 + s2 - ll = s3.toList() - self.assertEqual(s3.toList(), [1, 2, 3, 4]) - self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - s1 = s1 + s2 - self.assertEqual(s1.toList(), [1, 2, 3, 4]) - self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - - def test_stream_add_with_function_and_generator(self): - s1 = stream(lambda: range(1, 3)) - s2 = stream(range(3, 5)) - s3 = s1 + s2 - ll = s3.toList() - self.assertEqual(s3.toList(), [1, 2, 3, 4]) - self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - s1 = s1 + s2 - self.assertEqual(s1.toList(), [1, 2, 3, 4]) - self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - - def test_stream_iadd(self): - s1 = stream([1, 2]) - s1 += [3, 4] - s1 += stream(xrange(5, 6)) # use xrange to cover the iterator case - s1 += stream(lambda: (i for i in xrange(6, 7))) # to cover the lambda - expected = list(range(1, 7)) - self.assertEqual(s1.toList(), expected) - self.assertEqual(s1.toList(), expected) # second time to exclude one time iterator bug - - def test_stream_iadd_generator(self): - s1 = stream([1, 2]) - s1 += (i for i in xrange(3, 4)) - s1 += stream(i for i in xrange(4, 5)) - expected = list(range(1, 5)) - self.assertEqual(s1.toList(), expected) - - def test_stream_iadd_func_and_xrange(self): - s1 = stream(lambda: ((i for i in xrange(1, 3)))) - s1 += stream(xrange(3, 4)) - expected = list(range(1, 4)) - self.assertEqual(s1.toList(), expected) - - def test_stream_getitem(self): - s = stream(i for i in xrange(1)) - self.assertEqual(s[0], 0) - - def test_stream_getitem_withGroupBy_functional(self): - s = stream(lambda: (i for i in xrange(10))) - sg = s.groupBySortedToList(lambda _: _ // 3) - expected = [] - while True: - try: - expected.append(sg[0]) - except StopIteration: - break - self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - - def test_stream_getitem_withGroupBySortedToList_generator(self): - s = stream(i for i in xrange(10)) - sg = s.groupBySortedToList(lambda _: _ // 3) - expected = [] - while True: - try: - expected.append(sg[0]) - except StopIteration: - break - self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - - def test_stream_getitem_withGroupBySortedToList_next(self): - s = stream(i for i in xrange(10)) - sg = s.groupBySortedToList(lambda _: _ // 3) - expected = [] - while True: - try: - expected.append(sg.next()) - except StopIteration: - break - self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - - def test_stream_getitem_withGroupBySorted_next(self): - s = stream(i for i in xrange(10)) - sg = s.groupBySorted(lambda _: _ // 3) - expected = [] - while True: - try: - t = sg[0] - expected.append((t[0], t[1].toList())) - except StopIteration: - break - self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - - def test_group_consecutive_numbers(self): - s = stream([-10, -8, -7, -6, 1, 2, 4, 5, -1, 7]) - result = [list(g) for g in s.group_consecutive()] - self.assertEqual(result, [[-10], [-8, -7, -6], [1, 2], [4, 5], [-1], [7]]) - - def test_group_consecutive_string_as_numbers_ordering(self): - order_fn = lambda x: int(x) - s = stream(['1', '10', '11', '20', '21', '22', '30', '31']) - result = [list(g) for g in s.group_consecutive(order_fn)] - self.assertEqual(result, [['1'], ['10', '11'], ['20', '21', '22'], ['30', '31']]) - - def test_permutation_ordering(self): - order_fn = list(permutations('abcd')).index - s = stream([ - ('a', 'b', 'c', 'd'), - ('a', 'c', 'b', 'd'), - ('a', 'c', 'd', 'b'), - ('a', 'd', 'b', 'c'), - ('d', 'b', 'c', 'a'), - ('d', 'c', 'a', 'b'), - ]) - result = [list(g) for g in s.group_consecutive(order_fn)] - expected = [[('a', 'b', 'c', 'd')], - [('a', 'c', 'b', 'd'), ('a', 'c', 'd', 'b'), ('a', 'd', 'b', 'c')], - [('d', 'b', 'c', 'a'), ('d', 'c', 'a', 'b')], - ] - self.assertEqual(result, expected) - - def test_fastFlatMap_nominal(self): - s = stream([[1, 2], [3, 4], [4, 5]]) - self.assertListEqual(s.fastFlatMap(poolSize=2).toList(), [1, 2, 3, 4, 4, 5]) - - def test_fastFlatMap_random_sleep_function(self): - s = stream([1, 2, 5, 3, 4]) - - def random_sleep(i): - time.sleep(random.randrange(0, 10) * 0.01) - return range(i) - - self.assertListEqual(s.fastFlatMap(random_sleep, poolSize=2).sorted(), - [0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]) - - def test_fastFlatMap_withPredicate(self): - s = stream(({1: 2, 3: 4}, {5: 6, 7: 8})) - self.assertEqual(s.fastFlatMap(dict.items).toSet(), set(((1, 2), (5, 6), (3, 4), (7, 8)))) - - def test_fastFlatMap_defaultIdentityFunction(self): - l = slist(({1: 2, 3: 4}, {5: 6, 7: 8})) - self.assertEqual(l.fastFlatMap().toSet(), set((1, 3, 5, 7))) + try: + s.gtmap(f, poolSize=4).toSet() + except TypeError as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, "return x * x") + return + self.fail("No expected exceptions has been raised") - def test_fastmap_time(self): - def sleepFunc(el): - time.sleep(0.3) - return el * el +class mtmapTestCase(unittest.TestCase): + def test_mtmap_nominal(self): s = stream(xrange(100)) - t1 = time.time() - res = s.fastmap(sleepFunc, poolSize=50).toSet() - dt = time.time() - t1 - expected = set(i * i for i in xrange(100)) - self.assertSetEqual(res, expected) - self.assertLessEqual(dt, 1.5) + res = s.mtmap(_rnd_sleep, poolSize=8, bufferSize=20).toList() + expected = [i * i for i in xrange(100)] + self.assertListEqual(res, expected) def test_mtmap_time(self): def sleepFunc(el): @@ -603,66 +461,33 @@ def sleepFunc(el): self.assertSetEqual(res, expected) self.assertLessEqual(dt, 1.5) - def test_fastmap_nominal(self): - s = stream(xrange(100)) - res = s.fastmap(lambda x: x * x, poolSize=4).toSet() - expected = set(i * i for i in xrange(100)) - self.assertSetEqual(res, expected) - - def test_mtmap_nominal(self): - s = stream(xrange(100)) - res = s.mtmap(_rnd_sleep, poolSize=8, bufferSize=20).toList() - expected = [i * i for i in xrange(100)] - self.assertListEqual(res, expected) - - def test_fastmap_one_el(self): - s = stream([1, ]) - res = s.fastmap(lambda x: x * x, poolSize=4).toSet() - expected = set((1,)) - self.assertSetEqual(res, expected) + def test_mtmap_reiteration(self): + l = stream(lambda: (xrange(i) for i in xrange(5))).mtmap(len) + self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) + self.assertEqual(l.toList(), [0, 1, 2, 3, 4]) def test_mtmap_one_el(self): - s = stream([1, ]) + s = stream( + [ + 1, + ] + ) res = s.mtmap(lambda x: x * x, poolSize=4).toList() expected = [1] self.assertListEqual(res, expected) - def test_fastmap_no_el(self): - s = stream([]) - res = s.fastmap(lambda x: x * x, poolSize=4).toSet() - expected = set() - self.assertSetEqual(res, expected) - def test_mtmap_no_el(self): s = stream([]) res = s.mtmap(lambda x: x * x, poolSize=4).toList() expected = [] self.assertListEqual(res, expected) - def test_fastmap_None_el(self): - s = stream([None]) - res = s.fastmap(lambda x: x, poolSize=4).toSet() - expected = set([None]) - self.assertSetEqual(res, expected) - def test_mtmap_None_el(self): s = stream([None]) res = s.mtmap(lambda x: x, poolSize=4).toList() expected = [None] self.assertListEqual(res, expected) - def test_fastmap_take_less(self): - arr = [] - - def m(i): - arr.append(i) - return i - - s = stream(range(100)).map(m).fastmap(lambda x: x, poolSize=4, bufferSize=5).take(20) - res = s.toList() - self.assertLessEqual(len(arr), 30) - self.assertEqual(len(res), 20) - def test_mtmap_take_less(self): arr = [] @@ -675,215 +500,563 @@ def m(i): self.assertLessEqual(len(arr), 25) self.assertEqual(len(res), 20) - def test_traceback_right_when_fastmap_raises_builtin_exception(self): + def test_mtmap_raises_exception(self): s = stream([None]) + with self.assertRaises(TypeError): + _ = s.mtmap(lambda x: x * x, poolSize=4).toSet() - def f(x): - return x * x - + def test_traceback_right_when_mtmap_raises_custom_exception(self): + s = stream([None]) try: - s.fastmap(f, poolSize=4).toSet() - except TypeError as e: - line = traceback.TracebackException.from_exception(e).stack[5].line - self.assertEqual(line, 'return x * x') + s.mtmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() + except SomeCustomException as e: + line = traceback.TracebackException.from_exception(e).stack[6].line + self.assertEqual(line, 'raise SomeCustomException("")') return self.fail("No expected exceptions has been raised") - def test_traceback_right_when_fastmap_raises_custom_exception(self): - class SomeCustomException(Exception): - def __init__(self, message): - self.message = message - - def __str__(self): # pragma: no cover - return 'APIError(code=%s)' % (self.message) - + def test_traceback_right_when_mtmap_raises_builtin_exception(self): s = stream([None]) def f(x): - raise SomeCustomException("") + return x * x try: - s.fastmap(f, poolSize=4).toSet() - except SomeCustomException as e: - line = traceback.TracebackException.from_exception(e).stack[5].line - self.assertEqual(line, 'raise SomeCustomException("")') + s.mtmap(f, poolSize=4).toSet() + except TypeError as e: + line = traceback.TracebackException.from_exception(e).stack[6].line + self.assertEqual(line, "return x * x") return self.fail("No expected exceptions has been raised") - def test_traceback_right_when_mpfastmap_raises_custom_exception(self): - s = stream([None]) - try: - s.mpfastmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() - except SomeCustomException as e: - line = traceback.TracebackException.from_exception(e).stack[5].line - self.assertEqual(line, 'raise SomeCustomException("")') - return - self.fail("No expected exceptions has been raised") - def test_traceback_right_when_mpmap_raises_custom_exception(self): - s = stream([None]) - try: - s.mpmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() - except SomeCustomException as e: - line = traceback.TracebackException.from_exception(e).stack[5].line - self.assertEqual(line, 'raise SomeCustomException("")') - return - self.fail("No expected exceptions has been raised") +class mpmapTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.N_processes = 10 + cls.pool = Pool(cls.N_processes) + + def test_mpmap_nominal(self): + s = stream(xrange(10)) + f = partial(pow, 2) + res = s.mpmap(f, poolSize=4).toSet() + expected = set(f(i) for i in xrange(10)) + self.assertSetEqual(res, expected) + + def test_mpmap_time(self): + N = 10 + s = stream(xrange(N)) + t1 = time.time() + res = s.mpmap(PICKABLE_SLEEP_FUNC, poolSize=10).toSet() + dt = time.time() - t1 + expected = set(i * i for i in xrange(N)) + self.assertSetEqual(res, expected) + self.assertLessEqual(dt, 2) + + def test_mpmap_one_el(self): + s = stream( + [ + 2, + ] + ) + f = partial(pow, 2) + res = s.mpmap(f, poolSize=4).toSet() + expected = set((4,)) + self.assertSetEqual(res, expected) + + def test_mpmap_no_el(self): + s = stream([]) + res = s.mpmap(lambda x: x * x, poolSize=4).toSet() + expected = set() + self.assertSetEqual(res, expected) + + def test_mpmap_None_el(self): + s = stream([None]) + res = s.mpmap(PICKABLE_DUMB_FUNCTION, poolSize=4).toSet() + expected = set([None]) + self.assertSetEqual(res, expected) + + # ToDo: fix the Pool.imap not true lazyness + @unittest.skip("Pool.imap has bug. Workaround: https://stackoverflow.com/Questions/5318936/Python-Multiprocessing-Pool-Lazy-Iteration") + def test_mpmap_take_less(self): + arr = [] + + def m(i): + arr.append(i) + return i + + s = stream(range(100)).map(m).mpmap(PICKABLE_DUMB_FUNCTION, poolSize=4, bufferSize=5).take(20) + res = s.toList() + self.assertLessEqual(len(arr), 30) + self.assertEqual(len(res), 20) + + def test_mpmap_raises_exception(self): + s = stream([None]) + f = partial(pow, 2) + with self.assertRaises(TypeError): + _ = s.mpmap(f, poolSize=4).toSet() + + def test_traceback_right_when_mpmap_raises_custom_exception(self): + s = stream([None]) + try: + s.mpmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() + except SomeCustomException as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, 'raise SomeCustomException("")') + return + self.fail("No expected exceptions has been raised") + + def test_mpmap_pids(self): + s = stream(range(100)) + distinct_pids = s.mpmap(PICKABLE_PID_GETTER, poolSize=10).toSet() + self.assertGreaterEqual(len(distinct_pids), 2) + self.assertEqual(self.N_processes, self.pool._processes) + self.assertNotIn(os.getpid(), distinct_pids) + + +class mpfastmapTestCase(unittest.TestCase): + @classmethod + def setUpClass(cls) -> None: + cls.N_processes = 10 + cls.pool = Pool(cls.N_processes) + + def test_mpfastmap_time(self): + N = self.N_processes + s = stream(xrange(N)) + t1 = time.time() + res = s.mpfastmap(PICKABLE_SLEEP_FUNC, poolSize=N).toSet() + dt = time.time() - t1 + expected = set(i * i for i in xrange(N)) + self.assertSetEqual(res, expected) + self.assertLessEqual(dt, 1.5) + + def test_traceback_right_when_mpfastmap_raises_custom_exception(self): + s = stream([None]) + try: + s.mpfastmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() + except SomeCustomException as e: + line = traceback.TracebackException.from_exception(e).stack[5].line + self.assertEqual(line, 'raise SomeCustomException("")') + return + self.fail("No expected exceptions has been raised") + + def test_mpfastmap_raises_exception(self): + s = stream([None]) + f = partial(pow, 2) + with self.assertRaises(TypeError): + res = s.mpfastmap(f, poolSize=4).toSet() + + def test_mpfastmap_time_with_sequential_mapping(self): + N = self.N_processes + t1 = time.time() + s = stream([0.2] * N + [10.0] * N) + res = s.mpfastmap(PICKABLE_SLEEP_EXACT, poolSize=N).take(N).toSet() + dt = time.time() - t1 + expected = { + 0.2, + } + self.assertSetEqual(res, expected) + self.assertLessEqual(dt, 4) + + def test_mpfastmap_nominal(self): + s = stream(xrange(10)) + f = partial(pow, 2) + res = s.mpfastmap(f, poolSize=4).toSet() + expected = set(f(i) for i in xrange(10)) + self.assertSetEqual(res, expected) + + def test_mpfastmap_one_el(self): + s = stream( + [ + 2, + ] + ) + f = partial(pow, 2) + res = s.mpfastmap(f, poolSize=4).toSet() + expected = set((4,)) + self.assertSetEqual(res, expected) + + def test_mpfastmap_no_el(self): + s = stream([]) + res = s.mpfastmap(lambda x: x * x, poolSize=4).toSet() + expected = set() + self.assertSetEqual(res, expected) + + def test_mpfastmap_None_el(self): + s = stream([None]) + res = s.mpfastmap(PICKABLE_DUMB_FUNCTION, poolSize=4).toSet() + expected = set([None]) + self.assertSetEqual(res, expected) + + # ToDo: fix the Pool.imap not true lazyness, as the Pool.imap is not trully lazy + @unittest.skip("Pool.imap has bug. Workaround: https://stackoverflow.com/Questions/5318936/Python-Multiprocessing-Pool-Lazy-Iteration") + def test_mpfastmap_take_less(self): + arr = [] + + def m(i): + arr.append(i) + return i + + s = stream(range(100)).map(m).mpfastmap(PICKABLE_DUMB_FUNCTION, poolSize=4, bufferSize=1).take(20) + res = s.toList() + self.assertLessEqual(len(arr), 30) + self.assertEqual(len(res), 20) + + +class StarmapsTestCase(unittest.TestCase): + def test_mpstarmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).mpstarmap(pow) + self.assertListEqual(s.toList(), [32, 9, 1000]) + # ToDo: Why does the next fails? + # self.assertListEqual(s.toList(), [32, 9, 1000]) + + def test_starmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).starmap(pow) + self.assertListEqual(s.toList(), [32, 9, 1000]) + self.assertListEqual(s.toList(), [32, 9, 1000]) + + def test_faststarmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).faststarmap(pow) + self.assertSetEqual(s.toSet(), {32, 9, 1000}) + self.assertSetEqual(s.toSet(), {32, 9, 1000}) + + def test_mtstarmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).mtstarmap(pow) + self.assertListEqual(s.toList(), [32, 9, 1000]) + self.assertListEqual(s.toList(), [32, 9, 1000]) + + def test_gtstarmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).gtstarmap(pow) + self.assertListEqual(s.toList(), [32, 9, 1000]) + self.assertListEqual(s.toList(), [32, 9, 1000]) + + def test_mpfaststarmap(self): + s = stream([(2, 5), (3, 2), (10, 3)]).mpfaststarmap(pow) + self.assertSetEqual(s.toSet(), {32, 9, 1000}) + + # ToDo: Why does the next fails? + # self.assertSetEqual(s.toSet(), {32, 9, 1000}) + + +class StreamTestCase(unittest.TestCase): + # def setUp(self): + # self.s = + + def test_fastFlatMap_reiteration(self): + l = stream(lambda: (xrange(i) for i in xrange(5))).fastFlatMap() + self.assertListEqual(sorted(l.toList()), sorted([0, 0, 1, 0, 1, 2, 0, 1, 2, 3])) + self.assertEqual(sorted(l.toList()), sorted([0, 0, 1, 0, 1, 2, 0, 1, 2, 3])) # second time to assert the regeneration of generator + + def testStream(self): + s = lambda: stream((1, 2, 3)) + self.assertEqual(list(ifilter(lambda i: i % 2 == 0, s())), [2]) + self.assertEqual(list(s().filter(lambda i: i % 2 == 0)), [2]) + self.assertEqual(s().filter(lambda i: i % 2 == 0).toList(), [2]) + self.assertEqual(s()[1], 2) + self.assertEqual(s()[1:].toList(), [2, 3]) + self.assertEqual(s().take(2).toList(), [1, 2]) + self.assertAlmostEqual(stream((0, 1, 2, 3)).filter(lambda x: x > 0).entropy(), 1.4591479) + self.assertEqual(stream([(1, 2), (3, 4)]).zip().toList(), [(1, 3), (2, 4)]) + + def test_filterFromGeneratorReinstantiatesProperly(self): + s = stream(lambda: (i for i in xrange(5))) + s = s.filter(lambda e: e % 2 == 0) + self.assertEqual(s.toList(), [0, 2, 4]) + self.assertEqual(s.toList(), [0, 2, 4]) + s = stream(xrange(5)).filter(lambda e: e % 2 == 0) + self.assertEqual(s.toList(), [0, 2, 4]) + self.assertEqual(s.toList(), [0, 2, 4]) + + def test_starfilter(self): + s = stream([(2, 5), (3, 2), (10, 3)]).starfilter(lambda x, y: x > y) + self.assertEqual(s.toList(), [(3, 2), (10, 3)]) + self.assertEqual(s.toList(), [(3, 2), (10, 3)]) + + def test_streamExists(self): + s = stream([0, 1]) + self.assertEqual(s.exists(lambda e: e == 0), True) + self.assertEqual(s.exists(lambda e: e == 2), False) + + def test_stream_str_doesntChangeStream(self): + s = stream(iter((1, 2, 3, 4))) + str(s) + self.assertListEqual(s.toList(), [1, 2, 3, 4]) + + def test_stream_repr_doesntChangeStream(self): + s = stream(iter((1, 2, 3, 4))) + repr(s) + self.assertListEqual(s.toList(), [1, 2, 3, 4]) + + @unittest.skip("Json lib depends on streamerate, so it would generate recursive imports") + def testStreamToJson(self): + j = stream((("a", 2), (3, 4))).toJson() + self.assertIsInstance(j, JsonList) + self.assertListEqual(j, [["a", 2], [3, 4]]) + + def testStreamsFromGenerator(self): + sg = stream(lambda: (i for i in range(4))) + self.assertEqual(sg.size(), 4) + self.assertEqual(sg.size(), 4) + self.assertEqual(sg.filter(lambda x: x > 1).toList(), [2, 3]) + self.assertEqual(sg.filter(lambda x: x > 1).toList(), [2, 3]) + self.assertEqual(sg.map(lambda x: x > 1).toList(), [False, False, True, True]) + self.assertEqual(sg.map(lambda x: x > 1).toList(), [False, False, True, True]) + self.assertEqual(sg.map(lambda i: i**2).enumerate().toList(), [(0, 0), (1, 1), (2, 4), (3, 9)]) + self.assertEqual(sg.reduce(lambda x, y: x + y, 5), 11) + self.assertListEqual(list(sg.batch(2)), [[0, 1], [2, 3]]) + self.assertListEqual(list(sg.batch(2)), [[0, 1], [2, 3]]) + + def test_next_from_gen(self): + # Next consumes from stream + sg = stream(lambda: (i for i in range(4))) + self.assertEqual(sg.next(), 0) + self.assertEqual(sg.next(), 1) + self.assertListEqual(list(sg), [2, 3]) + + def test_next_from_list(self): + # Next consumes from stream + sg = stream([i for i in range(4)]) + self.assertEqual(sg.next(), 0) + self.assertEqual(sg.next(), 1) + self.assertListEqual(list(sg), [2, 3]) + + def testStreamPickling(self): + sio = BytesIO() + expected = slist(slist((i,)) for i in xrange(10)) + expected.dumpToPickle(sio) + sio = BytesIO(sio.getvalue()) + + result = stream.loadFromPickled(sio) + self.assertListEqual(expected, list(result)) + + def test_StreamFileReading(self): + sio = BytesIO() + expected = slist(slist((i,)) for i in xrange(10)) + expected.dumpToPickle(sio) + sio = BytesIO(sio.getvalue()) + + result = stream.loadFromPickled(sio) + self.assertEqual(list(expected), list(result)) + + def test_flatMap_nominal(self): + s = stream([[1, 2], [3, 4], [4, 5]]) + self.assertListEqual(s.flatMap().toList(), [1, 2, 3, 4, 4, 5]) + + def test_flatMap_withPredicate(self): + s = stream(({1: 2, 3: 4}, {5: 6, 7: 8})) + self.assertEqual(s.flatMap(dict.items).toSet(), set(((1, 2), (5, 6), (3, 4), (7, 8)))) + + def test_flatMap_reiteration(self): + l = stream(lambda: (xrange(i) for i in xrange(5))).flatMap() + self.assertEqual(l.toList(), [0, 0, 1, 0, 1, 2, 0, 1, 2, 3]) + self.assertEqual(l.toList(), [0, 0, 1, 0, 1, 2, 0, 1, 2, 3]) # second time to assert the regeneration of generator + + def test_flatMap_defaultIdentityFunction(self): + l = slist(({1: 2, 3: 4}, {5: 6, 7: 8})) + self.assertEqual(l.flatMap().toSet(), set((1, 3, 5, 7))) + + def test_reduceUsesInitProperly(self): + self.assertEqual(slist([sset((1, 2)), sset((3, 4))]).reduce(lambda x, y: x.update(y)), set((1, 2, 3, 4))) + self.assertEqual(slist([sset((1, 2)), sset((3, 4))]).reduce(lambda x, y: x.update(y), sset()), set((1, 2, 3, 4))) + + def test_transform_nominal(self): + s = stream(range(4)) + + def f(itr): + for i in itr: + for j in range(i): + yield i + + self.assertListEqual(s.transform(f).toList(), [1, 2, 2, 3, 3, 3]) + + def test_shuffle_nominal(self): + l = list(range(100)) + s = stream(l).shuffle() + self.assertNotEqual(l, list(s)) + self.assertSetEqual(set(l), s.toSet()) + + def test_maxes(self): + self.assertEqual(stream(["a", "abc", "abcd", "defg", "cde"]).maxes(lambda s: len(s)), ["abcd", "defg"]) + + def test_mins(self): + self.assertEqual(stream(["abc", "a", "abcd", "defg", "cde"]).mins(lambda s: len(s)), ["a"]) + + def test_min_nominal(self): + self.assertEqual(stream([2, 1]).min(), 1) + self.assertEqual(stream(["abc", "a"]).min(key=len), "a") - def test_mtmap_raises_exception(self): - s = stream([None]) - with self.assertRaises(TypeError): - res = s.mtmap(lambda x: x * x, poolSize=4).toSet() + def test_min_raises_on_empty_sequence(self): + with self.assertRaises(ValueError): + stream().min() - def test_traceback_right_when_mtmap_raises_custom_exception(self): - s = stream([None]) - try: - s.mtmap(PICKABLE_FUNCTION_RAISES, poolSize=4).toSet() - except SomeCustomException as e: - line = traceback.TracebackException.from_exception(e).stack[6].line - self.assertEqual(line, 'raise SomeCustomException("")') - return - self.fail("No expected exceptions has been raised") + def test_min_default_nominal(self): + self.assertEqual(stream([2, 1]).min_default("default"), 1) + self.assertEqual(stream(["abc", "a"]).min_default("default", key=len), "a") + self.assertEqual(stream().min_default("default"), "default") - def test_mpmap_pids(self): - s = stream(range(100)) - distinct_pids = s.mpmap(PICKABLE_PID_GETTER, poolSize=10).toSet() - self.assertGreaterEqual(len(distinct_pids), 2) - self.assertEqual(self.N_processes, self.pool._processes) - self.assertNotIn(os.getpid(), distinct_pids) + def test_stream_add(self): + s1 = stream([1, 2]) + s2 = stream([3, 4]) + s3 = s1 + s2 + ll = s3.toList() + self.assertEqual(s3.toList(), [1, 2, 3, 4]) + self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug + s1 = s1 + s2 + self.assertEqual(s1.toList(), [1, 2, 3, 4]) + self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - def test_mpfastmap_time(self): - N = self.N_processes - s = stream(xrange(N)) - t1 = time.time() - res = s.mpfastmap(PICKABLE_SLEEP_FUNC, poolSize=N).toSet() - dt = time.time() - t1 - expected = set(i * i for i in xrange(N)) - self.assertSetEqual(res, expected) - self.assertLessEqual(dt, 4) + def test_stream_add_nonstream(self): + s1 = stream([1, 2]) + s2 = range(3, 5) + s3 = s1 + s2 + ll = s3.toList() + self.assertEqual(s3.toList(), [1, 2, 3, 4]) + self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug + s1 = s1 + s2 + self.assertEqual(s1.toList(), [1, 2, 3, 4]) + self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - def test_mpfastmap_time_with_sequential_mapping(self): - N = self.N_processes - t1 = time.time() - s = stream([0.2] * N + [10.0] * N) - s = s.map(PICKABLE_SLEEP_FUNC) - res = s.mpfastmap(PICKABLE_SLEEP_FUNC, poolSize=N).take(N).toSet() - dt = time.time() - t1 - expected = {(0.2 * 0.2) * (0.2 * 0.2), } - self.assertSetEqual(res, expected) - self.assertLessEqual(dt, 4) + def test_stream_add_with_function_and_generator(self): + s1 = stream(lambda: range(1, 3)) + s2 = stream(range(3, 5)) + s3 = s1 + s2 + ll = s3.toList() + self.assertEqual(s3.toList(), [1, 2, 3, 4]) + self.assertEqual(s3.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug + s1 = s1 + s2 + self.assertEqual(s1.toList(), [1, 2, 3, 4]) + self.assertEqual(s1.toList(), [1, 2, 3, 4]) # second time to exclude one time iterator bug - def test_mpfastmap_nominal(self): - s = stream(xrange(10)) - f = partial(pow, 2) - res = s.mpfastmap(f, poolSize=4).toSet() - expected = set(f(i) for i in xrange(10)) - self.assertSetEqual(res, expected) + def test_stream_iadd(self): + s1 = stream([1, 2]) + s1 += [3, 4] + s1 += stream(xrange(5, 6)) # use xrange to cover the iterator case + s1 += stream(lambda: (i for i in xrange(6, 7))) # to cover the lambda + expected = list(range(1, 7)) + self.assertEqual(s1.toList(), expected) + self.assertEqual(s1.toList(), expected) # second time to exclude one time iterator bug - def test_mpfastmap_one_el(self): - s = stream([2, ]) - f = partial(pow, 2) - res = s.mpfastmap(f, poolSize=4).toSet() - expected = set((4,)) - self.assertSetEqual(res, expected) + def test_stream_iadd_generator(self): + s1 = stream([1, 2]) + s1 += (i for i in xrange(3, 4)) + s1 += stream(i for i in xrange(4, 5)) + expected = list(range(1, 5)) + self.assertEqual(s1.toList(), expected) - def test_mpfastmap_no_el(self): - s = stream([]) - res = s.mpfastmap(lambda x: x * x, poolSize=4).toSet() - expected = set() - self.assertSetEqual(res, expected) + def test_stream_iadd_func_and_xrange(self): + s1 = stream(lambda: ((i for i in xrange(1, 3)))) + s1 += stream(xrange(3, 4)) + expected = list(range(1, 4)) + self.assertEqual(s1.toList(), expected) - def test_mpfastmap_None_el(self): - s = stream([None]) - res = s.mpfastmap(PICKABLE_DUMB_FUNCTION, poolSize=4).toSet() - expected = set([None]) - self.assertSetEqual(res, expected) + def test_stream_getitem(self): + s = stream(i for i in xrange(1)) + self.assertEqual(s[0], 0) - # ToDo: fix the Pool.imap not true lazyness - @unittest.skip( - "Pool.imap has bug. Workaround: https://stackoverflow.com/Questions/5318936/Python-Multiprocessing-Pool-Lazy-Iteration") - def test_mpfastmap_take_less(self): - arr = [] + def test_stream_getitem_withGroupBy_functional(self): + s = stream(lambda: (i for i in xrange(10))) + sg = s.groupBySortedToList(lambda _: _ // 3) + expected = [] + while True: + try: + expected.append(sg[0]) + except StopIteration: + break + self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - def m(i): - arr.append(i) - return i + def test_stream_getitem_withGroupBySortedToList_generator(self): + s = stream(i for i in xrange(10)) + sg = s.groupBySortedToList(lambda _: _ // 3) + expected = [] + while True: + try: + expected.append(sg[0]) + except StopIteration: + break + self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - s = stream(range(100)).map(m).mpfastmap(PICKABLE_DUMB_FUNCTION, poolSize=4, bufferSize=5).take(20) - res = s.toList() - self.assertLessEqual(len(arr), 30) - self.assertEqual(len(res), 20) + def test_stream_getitem_withGroupBySortedToList_next(self): + s = stream(i for i in xrange(10)) + sg = s.groupBySortedToList(lambda _: _ // 3) + expected = [] + while True: + try: + expected.append(sg.next()) + except StopIteration: + break + self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - def test_mpfastmap_raises_exception(self): - s = stream([None]) - f = partial(pow, 2) - with self.assertRaises(TypeError): - res = s.mpfastmap(f, poolSize=4).toSet() + def test_stream_getitem_withGroupBySorted_next(self): + s = stream(i for i in xrange(10)) + sg = s.groupBySorted(lambda _: _ // 3) + expected = [] + while True: + try: + t = sg[0] + expected.append((t[0], t[1].toList())) + except StopIteration: + break + self.assertListEqual(expected, [(0, [0, 1, 2]), (1, [3, 4, 5]), (2, [6, 7, 8]), (3, [9])]) - def test_mpmap_time(self): - N = 10 - s = stream(xrange(N)) - t1 = time.time() - res = s.mpmap(PICKABLE_SLEEP_FUNC, poolSize=10).toSet() - dt = time.time() - t1 - expected = set(i * i for i in xrange(N)) - self.assertSetEqual(res, expected) - self.assertLessEqual(dt, 2) + def test_group_consecutive_numbers(self): + s = stream([-10, -8, -7, -6, 1, 2, 4, 5, -1, 7]) + result = [list(g) for g in s.group_consecutive()] + self.assertEqual(result, [[-10], [-8, -7, -6], [1, 2], [4, 5], [-1], [7]]) - def test_mpmap_nominal(self): - s = stream(xrange(10)) - f = partial(pow, 2) - res = s.mpmap(f, poolSize=4).toSet() - expected = set(f(i) for i in xrange(10)) - self.assertSetEqual(res, expected) + def test_group_consecutive_string_as_numbers_ordering(self): + order_fn = lambda x: int(x) + s = stream(["1", "10", "11", "20", "21", "22", "30", "31"]) + result = [list(g) for g in s.group_consecutive(order_fn)] + self.assertEqual(result, [["1"], ["10", "11"], ["20", "21", "22"], ["30", "31"]]) - def test_mpmap_one_el(self): - s = stream([2, ]) - f = partial(pow, 2) - res = s.mpmap(f, poolSize=4).toSet() - expected = set((4,)) - self.assertSetEqual(res, expected) + def test_permutation_ordering(self): + order_fn = list(permutations("abcd")).index + s = stream( + [ + ("a", "b", "c", "d"), + ("a", "c", "b", "d"), + ("a", "c", "d", "b"), + ("a", "d", "b", "c"), + ("d", "b", "c", "a"), + ("d", "c", "a", "b"), + ] + ) + result = [list(g) for g in s.group_consecutive(order_fn)] + expected = [ + [("a", "b", "c", "d")], + [("a", "c", "b", "d"), ("a", "c", "d", "b"), ("a", "d", "b", "c")], + [("d", "b", "c", "a"), ("d", "c", "a", "b")], + ] + self.assertEqual(result, expected) - def test_mpmap_no_el(self): - s = stream([]) - res = s.mpmap(lambda x: x * x, poolSize=4).toSet() - expected = set() - self.assertSetEqual(res, expected) + def test_fastFlatMap_nominal(self): + s = stream([[1, 2], [3, 4], [4, 5]]) + self.assertListEqual(s.fastFlatMap(poolSize=2).toList(), [1, 2, 3, 4, 4, 5]) - def test_mpmap_None_el(self): - s = stream([None]) - res = s.mpmap(PICKABLE_DUMB_FUNCTION, poolSize=4).toSet() - expected = set([None]) - self.assertSetEqual(res, expected) + def test_fastFlatMap_random_sleep_function(self): + s = stream([1, 2, 5, 3, 4]) - # ToDo: fix the Pool.imap not true lazyness - @unittest.skip( - "Pool.imap has bug. Workaround: https://stackoverflow.com/Questions/5318936/Python-Multiprocessing-Pool-Lazy-Iteration") - def test_mpmap_take_less(self): - arr = [] + def random_sleep(i): + time.sleep(random.randrange(0, 10) * 0.01) + return range(i) - def m(i): - arr.append(i) - return i + self.assertListEqual(s.fastFlatMap(random_sleep, poolSize=2).sorted(), [0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]) - s = stream(range(100)).map(m).mpmap(PICKABLE_DUMB_FUNCTION, poolSize=4, bufferSize=5).take(20) - res = s.toList() - self.assertLessEqual(len(arr), 30) - self.assertEqual(len(res), 20) + def test_fastFlatMap_withPredicate(self): + s = stream(({1: 2, 3: 4}, {5: 6, 7: 8})) + self.assertEqual(s.fastFlatMap(dict.items).toSet(), set(((1, 2), (5, 6), (3, 4), (7, 8)))) - def test_mpmap_raises_exception(self): - s = stream([None]) - f = partial(pow, 2) - with self.assertRaises(TypeError): - res = s.mpmap(f, poolSize=4).toSet() + def test_fastFlatMap_defaultIdentityFunction(self): + l = slist(({1: 2, 3: 4}, {5: 6, 7: 8})) + self.assertEqual(l.fastFlatMap().toSet(), set((1, 3, 5, 7))) def test_distinct_nominal(self): s = stream([1, 2, 3, 1, 2]) self.assertListEqual(s.distinct().toList(), [1, 2, 3]) def test_distinct_mapping(self): - s = stream(['abc', 'def', 'a', 'b', 'ab']) - self.assertListEqual(s.distinct(len).toList(), ['abc', 'a', 'ab']) + s = stream(["abc", "def", "a", "b", "ab"]) + self.assertListEqual(s.distinct(len).toList(), ["abc", "a", "ab"]) def test_distinct_empty_stream(self): s = stream([]) @@ -911,37 +1084,37 @@ def test_mean_exception(self): stream([]).mean() def test_toSumCounter_nominal(self): - s = stream([('a', 2), ('a', 4), ('b', 2.1), ('b', 3), ('c', 2)]) - self.assertDictEqual(s.toSumCounter(), {'a': 6, 'b': 5.1, 'c': 2}) + s = stream([("a", 2), ("a", 4), ("b", 2.1), ("b", 3), ("c", 2)]) + self.assertDictEqual(s.toSumCounter(), {"a": 6, "b": 5.1, "c": 2}) def test_toSumCounter_onEmptyStream(self): s = stream([]) self.assertDictEqual(s.toSumCounter(), {}) def test_toSumCounter_onStrings(self): - s = stream([('a', 'b'), ('a', 'c')]) - self.assertDictEqual(s.toSumCounter(), {'a': 'bc'}) + s = stream([("a", "b"), ("a", "c")]) + self.assertDictEqual(s.toSumCounter(), {"a": "bc"}) def test_keyBy_nominal(self): - self.assertListEqual(stream(['a', 'bb', '']).keyBy(len).toList(), [(1, 'a'), (2, 'bb'), (0, '')]) + self.assertListEqual(stream(["a", "bb", ""]).keyBy(len).toList(), [(1, "a"), (2, "bb"), (0, "")]) def test_keys_nominal(self): - self.assertListEqual(stream([(1, 'a'), (2, 'bb'), (0, '')]).keystream().toList(), [1, 2, 0]) + self.assertListEqual(stream([(1, "a"), (2, "bb"), (0, "")]).keystream().toList(), [1, 2, 0]) def test_values_nominal(self): - self.assertListEqual(stream([(1, 'a'), (2, 'bb'), (0, '')]).values().toList(), ['a', 'bb', '']) + self.assertListEqual(stream([(1, "a"), (2, "bb"), (0, "")]).values().toList(), ["a", "bb", ""]) def test_toMap(self): self.assertDictEqual(stream(((1, 2), (3, 4))).toMap(), {1: 2, 3: 4}) def test_joinWithString(self): s = "|" - strings = ('a', 'b', 'c') + strings = ("a", "b", "c") self.assertEqual(stream(iter(strings)).join(s), s.join(strings)) def test_joinWithNone(self): s = "" - strings = ('a', 'b', 'c') + strings = ("a", "b", "c") self.assertEqual(stream(iter(strings)).join(), s.join(strings)) def test_joinWithFunction(self): @@ -953,12 +1126,12 @@ def __call__(self, *args, **kwargs): self.counter += 1 return str(self.counter) - strings = ('a', 'b', 'c') + strings = ("a", "b", "c") f = F() self.assertEqual(stream(iter(strings)).join(f), "a1b2c") def test_mkString(self): - streamToTest = stream(('a', 'b', 'c')) + streamToTest = stream(("a", "b", "c")) mock = MagicMock() joiner = "," streamToTest.join = mock @@ -988,16 +1161,16 @@ def test_tail_nominal(self): self.assertListEqual(s.tail(5).toList(), [15, 16, 17, 18, 19]) def test_round_robin_nominal(self): - s = stream(['ABC', 'D', 'EF']) - self.assertListEqual(s.roundrobin().toList(), ['A', 'D', 'E', 'B', 'F', 'C']) + s = stream(["ABC", "D", "EF"]) + self.assertListEqual(s.roundrobin().toList(), ["A", "D", "E", "B", "F", "C"]) def test_pad_with_nominal(self): s = stream(range(2)) self.assertListEqual(s.pad_with(5).take(5).toList(), [0, 1, 5, 5, 5]) def test_all_equal_nominal(self): - equal_s = stream('AAAAA') - distinct_s = stream('AAABAAA') + equal_s = stream("AAAAA") + distinct_s = stream("AAABAAA") self.assertTrue(equal_s.all_equal()) self.assertFalse(distinct_s.all_equal()) @@ -1034,77 +1207,65 @@ def test_len(self): def test_tqdm_nominal(self): N = 4 - FLT = r'(\d+\.\d+|\?)' + FLT = r"(\d+\.\d+|\?)" PYPY3_ANOMALY = "\x1b\[A\x1b\[A" s = stream(range(N)) out = io.StringIO() self.assertListEqual(list(range(N)), s.tqdm(file=out).toList()) - expected = (rf'\r0it \[00:00, {FLT}it/s\]' - rf'({PYPY3_ANOMALY})?' - rf'\r{N}it \[00:00, {FLT}it/s\]\n') + expected = rf"\r0it \[00:00, {FLT}it/s\]" rf"({PYPY3_ANOMALY})?" rf"\r{N}it \[00:00, {FLT}it/s\]\n" self.assertRegex(out.getvalue(), expected) def test_tqdm_total(self): N = 4 s = stream(range(N)) - FLT = r'(\d+\.\d+|\?)' - TM = r'(00:00|\?)' + FLT = r"(\d+\.\d+|\?)" + TM = r"(00:00|\?)" PYPY3_ANOMALY = "\x1b\[A\x1b\[A" out = io.StringIO() self.assertListEqual(list(range(N)), s.tqdm(total=N, file=out).toList()) - expected = (rf'\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]' - rf'({PYPY3_ANOMALY})?' - rf'\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n') + expected = rf"\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]" rf"({PYPY3_ANOMALY})?" rf"\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n" self.assertRegex(out.getvalue(), expected) def test_tqdm_containers(self): if sys.version_info[1] < 7: # no support for Py3.6 return N = 4 - FLT = r'(\d+\.\d+|\?)' - TM = r'(00:00|\?)' + FLT = r"(\d+\.\d+|\?)" + TM = r"(00:00|\?)" PYPY3_ANOMALY = "\x1b\[A\x1b\[A" s = stream(list(range(N))) out = io.StringIO() self.assertListEqual(list(range(N)), s.toList().tqdm(file=out).toList()) - expected = (rf'\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]' - rf'({PYPY3_ANOMALY})?' - rf'\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n') + expected = rf"\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]" rf"({PYPY3_ANOMALY})?" rf"\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n" self.assertRegex(out.getvalue(), expected) out = io.StringIO() self.assertListEqual(list(range(N)), s.toSet().tqdm(file=out).toList()) - expected = (rf'\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]' - rf'({PYPY3_ANOMALY})?' - rf'\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n') + expected = rf"\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]" rf"({PYPY3_ANOMALY})?" rf"\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n" self.assertRegex(out.getvalue(), expected) s = stream(((i, i + 1) for i in range(N))).toMap() self.assertListEqual([i for i in range(N)], s.tqdm(file=out).toList()) - expected = (rf'\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]' - rf'({PYPY3_ANOMALY})?' - rf'\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n') + expected = rf"\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]" rf"({PYPY3_ANOMALY})?" rf"\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n" self.assertRegex(out.getvalue(), expected) def test_TqdmMapper_total(self): N = 4 - FLT = r'(\d+\.\d+|\?)' - TM = r'(00:00|\?)' + FLT = r"(\d+\.\d+|\?)" + TM = r"(00:00|\?)" s = stream(range(N)) out = io.StringIO() self.assertListEqual(list(range(N)), s.map(TqdmMapper(total=N, file=out)).toList()) - expected = rf'\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]' \ - rf'(\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n)?' + expected = rf"\r 0%\| \| 0/{N} \[00:00<\?, \?it/s\]" rf"(\r100%\|##########\| {N}/{N} \[00:00<{TM}, {FLT}it/s\]\n)?" self.assertRegex(out.getvalue(), expected) def test_TqdmMapper_nominal(self): N = 4 - FLT = r'(\d+\.\d+|\?)' + FLT = r"(\d+\.\d+|\?)" s = stream(range(N)) out = io.StringIO() self.assertListEqual(list(range(N)), s.map(TqdmMapper(file=out)).toList()) - expected = rf'\r0it \[00:00, {FLT}it/s\]' \ - rf'(\r{N}it \[00:00, {FLT}it/s\]\n)?' + expected = rf"\r0it \[00:00, {FLT}it/s\]" rf"(\r{N}it \[00:00, {FLT}it/s\]\n)?" self.assertRegex(out.getvalue(), expected) def test_pydantic_stream_validation(self): @@ -1125,14 +1286,14 @@ def test_pydantic_slist_validation(self): """ if sys.version_info[1] < 7: # no support for Py3.6 return - if os.name != 'nt': + if os.name != "nt": return @validate_arguments(config=dict(arbitrary_types_allowed=True)) def f(x: slist[int]): return x - s = stream([1.49, '2']).toList() + s = stream([1.49, "2"]).toList() converted = f(s) self.assertEqual(converted, [1, 2]) self.assertIsInstance(converted, list) @@ -1154,7 +1315,7 @@ def test_map_stream(self): s = stream((("a", 2), (3, 4))) d = s.map_stream(dict) self.assertIsInstance(d, dict) - self.assertDictEqual(d, {'a': 2, 3: 4}) + self.assertDictEqual(d, {"a": 2, 3: 4}) def test_for_each_nominal(self): l = [] @@ -1175,15 +1336,14 @@ def test_add_observer_nominal(self): def test_add_observer_reiterate(self): l1 = [] s = stream(lambda: (i for i in xrange(3))).add_observer(l1.append) - result1 = s.toList() + _ = s.toList() # reiterate again on the same iterator to assure observers are initialized properly result2 = s.toList() self.assertListEqual(l1, [0, 1, 2, 0, 1, 2]) self.assertListEqual(result2, [0, 1, 2]) -""" -Allow for these test cases to be run from the command line -""" -if __name__ == '__main__': + +if __name__ == "__main__": + # Allow for these test cases to be run from the command line all_tests = unittest.TestLoader().loadTestsFromModule(sys.modules[__name__]) unittest.TextTestRunner(verbosity=2).run(all_tests) diff --git a/upload.bat b/upload.bat index 415d4f5..6cba2b2 100644 --- a/upload.bat +++ b/upload.bat @@ -1,3 +1,4 @@ -del ./dist/*.whl -python setup.py bdist_wheel %* +del .\dist\*.whl +del .\dist\*.gz +poetry build twine upload dist/*.whl -u asuiu --verbose \ No newline at end of file diff --git a/upload.sh b/upload.sh index 2c8ad02..61334dc 100644 --- a/upload.sh +++ b/upload.sh @@ -1,4 +1,4 @@ #!/bin/bash rm ./dist/*.whl -python setup.py sdist bdist_wheel +poetry build twine upload dist/*.whl \ No newline at end of file