From 24ca7c4e8a32bff02036170ab50c04ce8cb76ea5 Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Wed, 26 Mar 2025 14:19:20 -0600 Subject: [PATCH 01/10] Replace setup.py with pyproject.toml Signed-off-by: Zack Cerza --- pyproject.toml | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ setup.py | 45 --------------------------------------------- 2 files changed, 48 insertions(+), 45 deletions(-) create mode 100644 pyproject.toml delete mode 100644 setup.py diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..826e047 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,48 @@ +[project] +name = "shaman" +authors = [ + {name = "Alfredo Deza"}, + {name = "Kyr Shatskyy", email = "kyrylo.shatskyy@clyso.com"}, +] +version = "0.1" +description = "" +readme = "README.rst" +license = {text = "MIT"} +requires-python = ">=3.10" +dependencies = [ + "pecan", + "sqlalchemy==1.4.53", + "psycopg2-binary==2.9.9", + "pecan-notario", + "requests", + "jinja2", + "pika", +] +classifiers = [ + 'Development Status :: 4 - Beta', + 'Intended Audience :: Developers', + 'Topic :: Utilities', + 'Operating System :: POSIX', + 'Programming Language :: Python :: 3.10', + 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', +] + +[project.entry-points."pecan.command"] +populate = "shaman.commands.populate:PopulateCommand" + +[project.optional-dependencies] +test = [ + "pytest", + "mock", + "webtest", +] + +[build-system] +build-backend = "setuptools.build_meta" +requires = [ + "setuptools>=45", + "wheel", +] + +[tool.setuptools.packages.find] diff --git a/setup.py b/setup.py deleted file mode 100644 index e6f63e3..0000000 --- a/setup.py +++ /dev/null @@ -1,45 +0,0 @@ -# -*- coding: utf-8 -*- -try: - from setuptools import setup, find_packages -except ImportError: - from ez_setup import use_setuptools - use_setuptools() - from setuptools import setup, find_packages - -setup( - name='shaman', - version='0.1', - description='', - author='Alfredo Deza', - author_email='adeza@redhat.com', - license = "MIT", - install_requires=[ - "pecan", - "sqlalchemy==1.4.53", - "psycopg2-binary==2.9.9", - "pecan-notario", - "requests", - "jinja2", - "pika", - ], - test_suite='shaman', - zip_safe=False, - include_package_data=True, - packages=find_packages(exclude=['ez_setup']), - classifiers = [ - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: MIT License', - 'Topic :: Utilities', - 'Operating System :: MacOS :: MacOS X', - 'Operating System :: POSIX', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - ], - entry_points=""" - [pecan.command] - populate=shaman.commands.populate:PopulateCommand - """ - -) From eb167f9dd6a676bc1c237aac8de1e448753c3d8b Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Wed, 26 Mar 2025 14:20:21 -0600 Subject: [PATCH 02/10] Manage dependencies with uv Signed-off-by: Zack Cerza --- requirements.txt | 260 ++++++++++++++++++++- uv.lock | 584 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 833 insertions(+), 11 deletions(-) create mode 100644 uv.lock diff --git a/requirements.txt b/requirements.txt index 8c39792..984ccfc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,11 +1,249 @@ -psycopg2-binary==2.9.9 -gunicorn==19.6.0 -pecan==1.5.1 -sqlalchemy==1.4.53 -pecan-notario==0.0.3 -alembic==1.13.2 -ipython==5.0.0 -requests==2.25.1 -jinja2==3.1.4 -pika==1.2.0 -enum34==1.1.10 +# This file was autogenerated by uv via the following command: +# uv export --format requirements-txt -o ./requirements.txt +-e . +certifi==2025.1.31 \ + --hash=sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651 \ + --hash=sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe +charset-normalizer==3.4.1 \ + --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \ + --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \ + --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \ + --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \ + --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \ + --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \ + --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \ + --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \ + --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \ + --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \ + --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \ + --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \ + --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \ + --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \ + --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \ + --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \ + --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \ + --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \ + --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \ + --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \ + --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \ + --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \ + --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \ + --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \ + --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \ + --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \ + --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \ + --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \ + --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \ + --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \ + --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \ + --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \ + --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \ + --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \ + --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \ + --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \ + --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \ + --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \ + --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \ + --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \ + --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \ + --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \ + --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \ + --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \ + --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \ + --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \ + --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \ + --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \ + --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \ + --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \ + --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \ + --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \ + --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \ + --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616 +greenlet==3.1.1 ; platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64' \ + --hash=sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e \ + --hash=sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01 \ + --hash=sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1 \ + --hash=sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159 \ + --hash=sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563 \ + --hash=sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83 \ + --hash=sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9 \ + --hash=sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395 \ + --hash=sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942 \ + --hash=sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1 \ + --hash=sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441 \ + --hash=sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0 \ + --hash=sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1 \ + --hash=sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6 \ + --hash=sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39 \ + --hash=sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d \ + --hash=sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467 \ + --hash=sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475 \ + --hash=sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511 \ + --hash=sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822 \ + --hash=sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a \ + --hash=sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01 \ + --hash=sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80 \ + --hash=sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13 \ + --hash=sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b \ + --hash=sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc \ + --hash=sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff \ + --hash=sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120 \ + --hash=sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36 \ + --hash=sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a \ + --hash=sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7 \ + --hash=sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761 \ + --hash=sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0 \ + --hash=sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e \ + --hash=sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa \ + --hash=sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c \ + --hash=sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e \ + --hash=sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617 \ + --hash=sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383 \ + --hash=sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70 \ + --hash=sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6 \ + --hash=sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4 \ + --hash=sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011 \ + --hash=sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79 +idna==3.10 \ + --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ + --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 +jinja2==3.1.6 \ + --hash=sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d \ + --hash=sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67 +legacy-cgi==2.6.2 ; python_full_version >= '3.13' \ + --hash=sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f \ + --hash=sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff +mako==1.3.9 \ + --hash=sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1 \ + --hash=sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac +markupsafe==3.0.2 \ + --hash=sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4 \ + --hash=sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30 \ + --hash=sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028 \ + --hash=sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca \ + --hash=sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557 \ + --hash=sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832 \ + --hash=sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b \ + --hash=sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579 \ + --hash=sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a \ + --hash=sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c \ + --hash=sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c \ + --hash=sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22 \ + --hash=sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094 \ + --hash=sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb \ + --hash=sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e \ + --hash=sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5 \ + --hash=sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a \ + --hash=sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8 \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158 \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48 \ + --hash=sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171 \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6 \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d \ + --hash=sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1 \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca \ + --hash=sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a \ + --hash=sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe \ + --hash=sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798 \ + --hash=sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 \ + --hash=sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50 +notario==0.0.16 \ + --hash=sha256:71c7d1254857c0832b928979ae47be15118724b83b5e7bb2e5fe0acbdc652f78 +pecan==1.6.0 \ + --hash=sha256:5fd4469583eed2ded37b4d10a470e11a5de3f3c963dc87984e772e25c56fed3e \ + --hash=sha256:f23e79b0a3bfc6bacef494b9aaeacc7f1896a55de00b2aae62372e6dcd371aeb +pecan-notario==0.0.3 \ + --hash=sha256:92114160ee39832d9dd523f1859ea9ba7d8260a0972eb5140fda9cfc39fd8536 +pika==1.3.2 \ + --hash=sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f \ + --hash=sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f +psycopg2-binary==2.9.9 \ + --hash=sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e \ + --hash=sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84 \ + --hash=sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2 \ + --hash=sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f \ + --hash=sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493 \ + --hash=sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996 \ + --hash=sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682 \ + --hash=sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe \ + --hash=sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93 \ + --hash=sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119 \ + --hash=sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b \ + --hash=sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2 \ + --hash=sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc \ + --hash=sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c \ + --hash=sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab \ + --hash=sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9 \ + --hash=sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf \ + --hash=sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0 \ + --hash=sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f \ + --hash=sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212 \ + --hash=sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb \ + --hash=sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be \ + --hash=sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d \ + --hash=sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245 \ + --hash=sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27 \ + --hash=sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417 \ + --hash=sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359 \ + --hash=sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202 \ + --hash=sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0 \ + --hash=sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7 \ + --hash=sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba \ + --hash=sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07 \ + --hash=sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98 \ + --hash=sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d \ + --hash=sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e \ + --hash=sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26 \ + --hash=sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53 +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 +setuptools==78.1.0 \ + --hash=sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54 \ + --hash=sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8 +sqlalchemy==1.4.53 \ + --hash=sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed \ + --hash=sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05 \ + --hash=sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae \ + --hash=sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22 \ + --hash=sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883 \ + --hash=sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9 \ + --hash=sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530 \ + --hash=sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525 \ + --hash=sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d \ + --hash=sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315 \ + --hash=sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69 \ + --hash=sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499 \ + --hash=sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c \ + --hash=sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da \ + --hash=sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7 \ + --hash=sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046 \ + --hash=sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330 \ + --hash=sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc +urllib3==2.3.0 \ + --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \ + --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d +webob==1.8.9 \ + --hash=sha256:45e34c58ed0c7e2ecd238ffd34432487ff13d9ad459ddfd77895e67abba7c1f9 \ + --hash=sha256:ad6078e2edb6766d1334ec3dee072ac6a7f95b1e32ce10def8ff7f0f02d56589 diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..a844b4f --- /dev/null +++ b/uv.lock @@ -0,0 +1,584 @@ +version = 1 +revision = 1 +requires-python = ">=3.10" +resolution-markers = [ + "python_full_version >= '3.13'", + "python_full_version < '3.13'", +] + +[[package]] +name = "beautifulsoup4" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f0/3c/adaf39ce1fb4afdd21b611e3d530b183bb7759c9b673d60db0e347fd4439/beautifulsoup4-4.13.3.tar.gz", hash = "sha256:1bd32405dacc920b42b83ba01644747ed77456a65760e285fbc47633ceddaf8b", size = 619516 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/49/6abb616eb3cbab6a7cca303dc02fdf3836de2e0b834bf966a7f5271a34d8/beautifulsoup4-4.13.3-py3-none-any.whl", hash = "sha256:99045d7d3f08f91f0d656bc9b7efbae189426cd913d830294a15eefa0ea4df16", size = 186015 }, +] + +[[package]] +name = "certifi" +version = "2025.1.31" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1c/ab/c9f1e32b7b1bf505bf26f0ef697775960db7932abeb7b516de930ba2705f/certifi-2025.1.31.tar.gz", hash = "sha256:3d5da6925056f6f18f119200434a4780a94263f10d1c21d032a6f6b2baa20651", size = 167577 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/fc/bce832fd4fd99766c04d1ee0eead6b0ec6486fb100ae5e74c1d91292b982/certifi-2025.1.31-py3-none-any.whl", hash = "sha256:ca78db4565a652026a4db2bcdf68f2fb589ea80d0be70e03929ed730746b84fe", size = 166393 }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/16/b0/572805e227f01586461c80e0fd25d65a2115599cc9dad142fee4b747c357/charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3", size = 123188 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/58/5580c1716040bc89206c77d8f74418caf82ce519aae06450393ca73475d1/charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de", size = 198013 }, + { url = "https://files.pythonhosted.org/packages/d0/11/00341177ae71c6f5159a08168bcb98c6e6d196d372c94511f9f6c9afe0c6/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176", size = 141285 }, + { url = "https://files.pythonhosted.org/packages/01/09/11d684ea5819e5a8f5100fb0b38cf8d02b514746607934134d31233e02c8/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037", size = 151449 }, + { url = "https://files.pythonhosted.org/packages/08/06/9f5a12939db324d905dc1f70591ae7d7898d030d7662f0d426e2286f68c9/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f", size = 143892 }, + { url = "https://files.pythonhosted.org/packages/93/62/5e89cdfe04584cb7f4d36003ffa2936681b03ecc0754f8e969c2becb7e24/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a", size = 146123 }, + { url = "https://files.pythonhosted.org/packages/a9/ac/ab729a15c516da2ab70a05f8722ecfccc3f04ed7a18e45c75bbbaa347d61/charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a", size = 147943 }, + { url = "https://files.pythonhosted.org/packages/03/d2/3f392f23f042615689456e9a274640c1d2e5dd1d52de36ab8f7955f8f050/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247", size = 142063 }, + { url = "https://files.pythonhosted.org/packages/f2/e3/e20aae5e1039a2cd9b08d9205f52142329f887f8cf70da3650326670bddf/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408", size = 150578 }, + { url = "https://files.pythonhosted.org/packages/8d/af/779ad72a4da0aed925e1139d458adc486e61076d7ecdcc09e610ea8678db/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb", size = 153629 }, + { url = "https://files.pythonhosted.org/packages/c2/b6/7aa450b278e7aa92cf7732140bfd8be21f5f29d5bf334ae987c945276639/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d", size = 150778 }, + { url = "https://files.pythonhosted.org/packages/39/f4/d9f4f712d0951dcbfd42920d3db81b00dd23b6ab520419626f4023334056/charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807", size = 146453 }, + { url = "https://files.pythonhosted.org/packages/49/2b/999d0314e4ee0cff3cb83e6bc9aeddd397eeed693edb4facb901eb8fbb69/charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f", size = 95479 }, + { url = "https://files.pythonhosted.org/packages/2d/ce/3cbed41cff67e455a386fb5e5dd8906cdda2ed92fbc6297921f2e4419309/charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f", size = 102790 }, + { url = "https://files.pythonhosted.org/packages/72/80/41ef5d5a7935d2d3a773e3eaebf0a9350542f2cab4eac59a7a4741fbbbbe/charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125", size = 194995 }, + { url = "https://files.pythonhosted.org/packages/7a/28/0b9fefa7b8b080ec492110af6d88aa3dea91c464b17d53474b6e9ba5d2c5/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1", size = 139471 }, + { url = "https://files.pythonhosted.org/packages/71/64/d24ab1a997efb06402e3fc07317e94da358e2585165930d9d59ad45fcae2/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3", size = 149831 }, + { url = "https://files.pythonhosted.org/packages/37/ed/be39e5258e198655240db5e19e0b11379163ad7070962d6b0c87ed2c4d39/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd", size = 142335 }, + { url = "https://files.pythonhosted.org/packages/88/83/489e9504711fa05d8dde1574996408026bdbdbd938f23be67deebb5eca92/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00", size = 143862 }, + { url = "https://files.pythonhosted.org/packages/c6/c7/32da20821cf387b759ad24627a9aca289d2822de929b8a41b6241767b461/charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12", size = 145673 }, + { url = "https://files.pythonhosted.org/packages/68/85/f4288e96039abdd5aeb5c546fa20a37b50da71b5cf01e75e87f16cd43304/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77", size = 140211 }, + { url = "https://files.pythonhosted.org/packages/28/a3/a42e70d03cbdabc18997baf4f0227c73591a08041c149e710045c281f97b/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146", size = 148039 }, + { url = "https://files.pythonhosted.org/packages/85/e4/65699e8ab3014ecbe6f5c71d1a55d810fb716bbfd74f6283d5c2aa87febf/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd", size = 151939 }, + { url = "https://files.pythonhosted.org/packages/b1/82/8e9fe624cc5374193de6860aba3ea8070f584c8565ee77c168ec13274bd2/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6", size = 149075 }, + { url = "https://files.pythonhosted.org/packages/3d/7b/82865ba54c765560c8433f65e8acb9217cb839a9e32b42af4aa8e945870f/charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8", size = 144340 }, + { url = "https://files.pythonhosted.org/packages/b5/b6/9674a4b7d4d99a0d2df9b215da766ee682718f88055751e1e5e753c82db0/charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b", size = 95205 }, + { url = "https://files.pythonhosted.org/packages/1e/ab/45b180e175de4402dcf7547e4fb617283bae54ce35c27930a6f35b6bef15/charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76", size = 102441 }, + { url = "https://files.pythonhosted.org/packages/0a/9a/dd1e1cdceb841925b7798369a09279bd1cf183cef0f9ddf15a3a6502ee45/charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545", size = 196105 }, + { url = "https://files.pythonhosted.org/packages/d3/8c/90bfabf8c4809ecb648f39794cf2a84ff2e7d2a6cf159fe68d9a26160467/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7", size = 140404 }, + { url = "https://files.pythonhosted.org/packages/ad/8f/e410d57c721945ea3b4f1a04b74f70ce8fa800d393d72899f0a40526401f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757", size = 150423 }, + { url = "https://files.pythonhosted.org/packages/f0/b8/e6825e25deb691ff98cf5c9072ee0605dc2acfca98af70c2d1b1bc75190d/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa", size = 143184 }, + { url = "https://files.pythonhosted.org/packages/3e/a2/513f6cbe752421f16d969e32f3583762bfd583848b763913ddab8d9bfd4f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d", size = 145268 }, + { url = "https://files.pythonhosted.org/packages/74/94/8a5277664f27c3c438546f3eb53b33f5b19568eb7424736bdc440a88a31f/charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616", size = 147601 }, + { url = "https://files.pythonhosted.org/packages/7c/5f/6d352c51ee763623a98e31194823518e09bfa48be2a7e8383cf691bbb3d0/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b", size = 141098 }, + { url = "https://files.pythonhosted.org/packages/78/d4/f5704cb629ba5ab16d1d3d741396aec6dc3ca2b67757c45b0599bb010478/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d", size = 149520 }, + { url = "https://files.pythonhosted.org/packages/c5/96/64120b1d02b81785f222b976c0fb79a35875457fa9bb40827678e54d1bc8/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a", size = 152852 }, + { url = "https://files.pythonhosted.org/packages/84/c9/98e3732278a99f47d487fd3468bc60b882920cef29d1fa6ca460a1fdf4e6/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9", size = 150488 }, + { url = "https://files.pythonhosted.org/packages/13/0e/9c8d4cb99c98c1007cc11eda969ebfe837bbbd0acdb4736d228ccaabcd22/charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1", size = 146192 }, + { url = "https://files.pythonhosted.org/packages/b2/21/2b6b5b860781a0b49427309cb8670785aa543fb2178de875b87b9cc97746/charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35", size = 95550 }, + { url = "https://files.pythonhosted.org/packages/21/5b/1b390b03b1d16c7e382b561c5329f83cc06623916aab983e8ab9239c7d5c/charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f", size = 102785 }, + { url = "https://files.pythonhosted.org/packages/38/94/ce8e6f63d18049672c76d07d119304e1e2d7c6098f0841b51c666e9f44a0/charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda", size = 195698 }, + { url = "https://files.pythonhosted.org/packages/24/2e/dfdd9770664aae179a96561cc6952ff08f9a8cd09a908f259a9dfa063568/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313", size = 140162 }, + { url = "https://files.pythonhosted.org/packages/24/4e/f646b9093cff8fc86f2d60af2de4dc17c759de9d554f130b140ea4738ca6/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9", size = 150263 }, + { url = "https://files.pythonhosted.org/packages/5e/67/2937f8d548c3ef6e2f9aab0f6e21001056f692d43282b165e7c56023e6dd/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b", size = 142966 }, + { url = "https://files.pythonhosted.org/packages/52/ed/b7f4f07de100bdb95c1756d3a4d17b90c1a3c53715c1a476f8738058e0fa/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11", size = 144992 }, + { url = "https://files.pythonhosted.org/packages/96/2c/d49710a6dbcd3776265f4c923bb73ebe83933dfbaa841c5da850fe0fd20b/charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f", size = 147162 }, + { url = "https://files.pythonhosted.org/packages/b4/41/35ff1f9a6bd380303dea55e44c4933b4cc3c4850988927d4082ada230273/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd", size = 140972 }, + { url = "https://files.pythonhosted.org/packages/fb/43/c6a0b685fe6910d08ba971f62cd9c3e862a85770395ba5d9cad4fede33ab/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2", size = 149095 }, + { url = "https://files.pythonhosted.org/packages/4c/ff/a9a504662452e2d2878512115638966e75633519ec11f25fca3d2049a94a/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886", size = 152668 }, + { url = "https://files.pythonhosted.org/packages/6c/71/189996b6d9a4b932564701628af5cee6716733e9165af1d5e1b285c530ed/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601", size = 150073 }, + { url = "https://files.pythonhosted.org/packages/e4/93/946a86ce20790e11312c87c75ba68d5f6ad2208cfb52b2d6a2c32840d922/charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd", size = 145732 }, + { url = "https://files.pythonhosted.org/packages/cd/e5/131d2fb1b0dddafc37be4f3a2fa79aa4c037368be9423061dccadfd90091/charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407", size = 95391 }, + { url = "https://files.pythonhosted.org/packages/27/f2/4f9a69cc7712b9b5ad8fdb87039fd89abba997ad5cbe690d1835d40405b0/charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971", size = 102702 }, + { url = "https://files.pythonhosted.org/packages/0e/f6/65ecc6878a89bb1c23a086ea335ad4bf21a588990c3f535a227b9eea9108/charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85", size = 49767 }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 }, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/35/2495c4ac46b980e4ca1f6ad6db102322ef3ad2410b79fdde159a4b0f3b92/exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc", size = 28883 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/02/cc/b7e31358aac6ed1ef2bb790a9746ac2c69bcb3c8588b41616914eb106eaf/exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", size = 16453 }, +] + +[[package]] +name = "greenlet" +version = "3.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2f/ff/df5fede753cc10f6a5be0931204ea30c35fa2f2ea7a35b25bdaf4fe40e46/greenlet-3.1.1.tar.gz", hash = "sha256:4ce3ac6cdb6adf7946475d7ef31777c26d94bccc377e070a7986bd2d5c515467", size = 186022 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/90/5234a78dc0ef6496a6eb97b67a42a8e96742a56f7dc808cb954a85390448/greenlet-3.1.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:0bbae94a29c9e5c7e4a2b7f0aae5c17e8e90acbfd3bf6270eeba60c39fce3563", size = 271235 }, + { url = "https://files.pythonhosted.org/packages/7c/16/cd631fa0ab7d06ef06387135b7549fdcc77d8d859ed770a0d28e47b20972/greenlet-3.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fde093fb93f35ca72a556cf72c92ea3ebfda3d79fc35bb19fbe685853869a83", size = 637168 }, + { url = "https://files.pythonhosted.org/packages/2f/b1/aed39043a6fec33c284a2c9abd63ce191f4f1a07319340ffc04d2ed3256f/greenlet-3.1.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:36b89d13c49216cadb828db8dfa6ce86bbbc476a82d3a6c397f0efae0525bdd0", size = 648826 }, + { url = "https://files.pythonhosted.org/packages/76/25/40e0112f7f3ebe54e8e8ed91b2b9f970805143efef16d043dfc15e70f44b/greenlet-3.1.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b6150a85e1b33b40b1464a3f9988dcc5251d6ed06842abff82e42632fac120", size = 644443 }, + { url = "https://files.pythonhosted.org/packages/fb/2f/3850b867a9af519794784a7eeed1dd5bc68ffbcc5b28cef703711025fd0a/greenlet-3.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93147c513fac16385d1036b7e5b102c7fbbdb163d556b791f0f11eada7ba65dc", size = 643295 }, + { url = "https://files.pythonhosted.org/packages/cf/69/79e4d63b9387b48939096e25115b8af7cd8a90397a304f92436bcb21f5b2/greenlet-3.1.1-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da7a9bff22ce038e19bf62c4dd1ec8391062878710ded0a845bcf47cc0200617", size = 599544 }, + { url = "https://files.pythonhosted.org/packages/46/1d/44dbcb0e6c323bd6f71b8c2f4233766a5faf4b8948873225d34a0b7efa71/greenlet-3.1.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:b2795058c23988728eec1f36a4e5e4ebad22f8320c85f3587b539b9ac84128d7", size = 1125456 }, + { url = "https://files.pythonhosted.org/packages/e0/1d/a305dce121838d0278cee39d5bb268c657f10a5363ae4b726848f833f1bb/greenlet-3.1.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ed10eac5830befbdd0c32f83e8aa6288361597550ba669b04c48f0f9a2c843c6", size = 1149111 }, + { url = "https://files.pythonhosted.org/packages/96/28/d62835fb33fb5652f2e98d34c44ad1a0feacc8b1d3f1aecab035f51f267d/greenlet-3.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:77c386de38a60d1dfb8e55b8c1101d68c79dfdd25c7095d51fec2dd800892b80", size = 298392 }, + { url = "https://files.pythonhosted.org/packages/28/62/1c2665558618553c42922ed47a4e6d6527e2fa3516a8256c2f431c5d0441/greenlet-3.1.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:e4d333e558953648ca09d64f13e6d8f0523fa705f51cae3f03b5983489958c70", size = 272479 }, + { url = "https://files.pythonhosted.org/packages/76/9d/421e2d5f07285b6e4e3a676b016ca781f63cfe4a0cd8eaecf3fd6f7a71ae/greenlet-3.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09fc016b73c94e98e29af67ab7b9a879c307c6731a2c9da0db5a7d9b7edd1159", size = 640404 }, + { url = "https://files.pythonhosted.org/packages/e5/de/6e05f5c59262a584e502dd3d261bbdd2c97ab5416cc9c0b91ea38932a901/greenlet-3.1.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d5e975ca70269d66d17dd995dafc06f1b06e8cb1ec1e9ed54c1d1e4a7c4cf26e", size = 652813 }, + { url = "https://files.pythonhosted.org/packages/49/93/d5f93c84241acdea15a8fd329362c2c71c79e1a507c3f142a5d67ea435ae/greenlet-3.1.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b2813dc3de8c1ee3f924e4d4227999285fd335d1bcc0d2be6dc3f1f6a318ec1", size = 648517 }, + { url = "https://files.pythonhosted.org/packages/15/85/72f77fc02d00470c86a5c982b8daafdf65d38aefbbe441cebff3bf7037fc/greenlet-3.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e347b3bfcf985a05e8c0b7d462ba6f15b1ee1c909e2dcad795e49e91b152c383", size = 647831 }, + { url = "https://files.pythonhosted.org/packages/f7/4b/1c9695aa24f808e156c8f4813f685d975ca73c000c2a5056c514c64980f6/greenlet-3.1.1-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e8f8c9cb53cdac7ba9793c276acd90168f416b9ce36799b9b885790f8ad6c0a", size = 602413 }, + { url = "https://files.pythonhosted.org/packages/76/70/ad6e5b31ef330f03b12559d19fda2606a522d3849cde46b24f223d6d1619/greenlet-3.1.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:62ee94988d6b4722ce0028644418d93a52429e977d742ca2ccbe1c4f4a792511", size = 1129619 }, + { url = "https://files.pythonhosted.org/packages/f4/fb/201e1b932e584066e0f0658b538e73c459b34d44b4bd4034f682423bc801/greenlet-3.1.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1776fd7f989fc6b8d8c8cb8da1f6b82c5814957264d1f6cf818d475ec2bf6395", size = 1155198 }, + { url = "https://files.pythonhosted.org/packages/12/da/b9ed5e310bb8b89661b80cbcd4db5a067903bbcd7fc854923f5ebb4144f0/greenlet-3.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:48ca08c771c268a768087b408658e216133aecd835c0ded47ce955381105ba39", size = 298930 }, + { url = "https://files.pythonhosted.org/packages/7d/ec/bad1ac26764d26aa1353216fcbfa4670050f66d445448aafa227f8b16e80/greenlet-3.1.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:4afe7ea89de619adc868e087b4d2359282058479d7cfb94970adf4b55284574d", size = 274260 }, + { url = "https://files.pythonhosted.org/packages/66/d4/c8c04958870f482459ab5956c2942c4ec35cac7fe245527f1039837c17a9/greenlet-3.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f406b22b7c9a9b4f8aa9d2ab13d6ae0ac3e85c9a809bd590ad53fed2bf70dc79", size = 649064 }, + { url = "https://files.pythonhosted.org/packages/51/41/467b12a8c7c1303d20abcca145db2be4e6cd50a951fa30af48b6ec607581/greenlet-3.1.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c3a701fe5a9695b238503ce5bbe8218e03c3bcccf7e204e455e7462d770268aa", size = 663420 }, + { url = "https://files.pythonhosted.org/packages/27/8f/2a93cd9b1e7107d5c7b3b7816eeadcac2ebcaf6d6513df9abaf0334777f6/greenlet-3.1.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2846930c65b47d70b9d178e89c7e1a69c95c1f68ea5aa0a58646b7a96df12441", size = 658035 }, + { url = "https://files.pythonhosted.org/packages/57/5c/7c6f50cb12be092e1dccb2599be5a942c3416dbcfb76efcf54b3f8be4d8d/greenlet-3.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99cfaa2110534e2cf3ba31a7abcac9d328d1d9f1b95beede58294a60348fba36", size = 660105 }, + { url = "https://files.pythonhosted.org/packages/f1/66/033e58a50fd9ec9df00a8671c74f1f3a320564c6415a4ed82a1c651654ba/greenlet-3.1.1-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1443279c19fca463fc33e65ef2a935a5b09bb90f978beab37729e1c3c6c25fe9", size = 613077 }, + { url = "https://files.pythonhosted.org/packages/19/c5/36384a06f748044d06bdd8776e231fadf92fc896bd12cb1c9f5a1bda9578/greenlet-3.1.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b7cede291382a78f7bb5f04a529cb18e068dd29e0fb27376074b6d0317bf4dd0", size = 1135975 }, + { url = "https://files.pythonhosted.org/packages/38/f9/c0a0eb61bdf808d23266ecf1d63309f0e1471f284300ce6dac0ae1231881/greenlet-3.1.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:23f20bb60ae298d7d8656c6ec6db134bca379ecefadb0b19ce6f19d1f232a942", size = 1163955 }, + { url = "https://files.pythonhosted.org/packages/43/21/a5d9df1d21514883333fc86584c07c2b49ba7c602e670b174bd73cfc9c7f/greenlet-3.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:7124e16b4c55d417577c2077be379514321916d5790fa287c9ed6f23bd2ffd01", size = 299655 }, + { url = "https://files.pythonhosted.org/packages/f3/57/0db4940cd7bb461365ca8d6fd53e68254c9dbbcc2b452e69d0d41f10a85e/greenlet-3.1.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:05175c27cb459dcfc05d026c4232f9de8913ed006d42713cb8a5137bd49375f1", size = 272990 }, + { url = "https://files.pythonhosted.org/packages/1c/ec/423d113c9f74e5e402e175b157203e9102feeb7088cee844d735b28ef963/greenlet-3.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:935e943ec47c4afab8965954bf49bfa639c05d4ccf9ef6e924188f762145c0ff", size = 649175 }, + { url = "https://files.pythonhosted.org/packages/a9/46/ddbd2db9ff209186b7b7c621d1432e2f21714adc988703dbdd0e65155c77/greenlet-3.1.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:667a9706c970cb552ede35aee17339a18e8f2a87a51fba2ed39ceeeb1004798a", size = 663425 }, + { url = "https://files.pythonhosted.org/packages/bc/f9/9c82d6b2b04aa37e38e74f0c429aece5eeb02bab6e3b98e7db89b23d94c6/greenlet-3.1.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b8a678974d1f3aa55f6cc34dc480169d58f2e6d8958895d68845fa4ab566509e", size = 657736 }, + { url = "https://files.pythonhosted.org/packages/d9/42/b87bc2a81e3a62c3de2b0d550bf91a86939442b7ff85abb94eec3fc0e6aa/greenlet-3.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efc0f674aa41b92da8c49e0346318c6075d734994c3c4e4430b1c3f853e498e4", size = 660347 }, + { url = "https://files.pythonhosted.org/packages/37/fa/71599c3fd06336cdc3eac52e6871cfebab4d9d70674a9a9e7a482c318e99/greenlet-3.1.1-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0153404a4bb921f0ff1abeb5ce8a5131da56b953eda6e14b88dc6bbc04d2049e", size = 615583 }, + { url = "https://files.pythonhosted.org/packages/4e/96/e9ef85de031703ee7a4483489b40cf307f93c1824a02e903106f2ea315fe/greenlet-3.1.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:275f72decf9932639c1c6dd1013a1bc266438eb32710016a1c742df5da6e60a1", size = 1133039 }, + { url = "https://files.pythonhosted.org/packages/87/76/b2b6362accd69f2d1889db61a18c94bc743e961e3cab344c2effaa4b4a25/greenlet-3.1.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:c4aab7f6381f38a4b42f269057aee279ab0fc7bf2e929e3d4abfae97b682a12c", size = 1160716 }, + { url = "https://files.pythonhosted.org/packages/1f/1b/54336d876186920e185066d8c3024ad55f21d7cc3683c856127ddb7b13ce/greenlet-3.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:b42703b1cf69f2aa1df7d1030b9d77d3e584a70755674d60e710f0af570f3761", size = 299490 }, + { url = "https://files.pythonhosted.org/packages/5f/17/bea55bf36990e1638a2af5ba10c1640273ef20f627962cf97107f1e5d637/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1695e76146579f8c06c1509c7ce4dfe0706f49c6831a817ac04eebb2fd02011", size = 643731 }, + { url = "https://files.pythonhosted.org/packages/78/d2/aa3d2157f9ab742a08e0fd8f77d4699f37c22adfbfeb0c610a186b5f75e0/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7876452af029456b3f3549b696bb36a06db7c90747740c5302f74a9e9fa14b13", size = 649304 }, + { url = "https://files.pythonhosted.org/packages/f1/8e/d0aeffe69e53ccff5a28fa86f07ad1d2d2d6537a9506229431a2a02e2f15/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ead44c85f8ab905852d3de8d86f6f8baf77109f9da589cb4fa142bd3b57b475", size = 646537 }, + { url = "https://files.pythonhosted.org/packages/05/79/e15408220bbb989469c8871062c97c6c9136770657ba779711b90870d867/greenlet-3.1.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8320f64b777d00dd7ccdade271eaf0cad6636343293a25074cc5566160e4de7b", size = 642506 }, + { url = "https://files.pythonhosted.org/packages/18/87/470e01a940307796f1d25f8167b551a968540fbe0551c0ebb853cb527dd6/greenlet-3.1.1-cp313-cp313t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6510bf84a6b643dabba74d3049ead221257603a253d0a9873f55f6a59a65f822", size = 602753 }, + { url = "https://files.pythonhosted.org/packages/e2/72/576815ba674eddc3c25028238f74d7b8068902b3968cbe456771b166455e/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:04b013dc07c96f83134b1e99888e7a79979f1a247e2a9f59697fa14b5862ed01", size = 1122731 }, + { url = "https://files.pythonhosted.org/packages/ac/38/08cc303ddddc4b3d7c628c3039a61a3aae36c241ed01393d00c2fd663473/greenlet-3.1.1-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:411f015496fec93c1c8cd4e5238da364e1da7a124bcb293f085bf2860c32c6f6", size = 1142112 }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442 }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050 }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899 }, +] + +[[package]] +name = "legacy-cgi" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ad/2e/e1860989bc6cfdecba66db37f2f783636b97a1248ac25fbe864b6e931c22/legacy_cgi-2.6.2.tar.gz", hash = "sha256:9952471ceb304043b104c22d00b4f333cac27a6abe446d8a528fc437cf13c85f", size = 24794 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/cd/54d1fd92d7f6aca9523d8583052e00b273bdfe28aa7fd54a3a5759dab05e/legacy_cgi-2.6.2-py3-none-any.whl", hash = "sha256:a7b83afb1baf6ebeb56522537c5943ef9813cf933f6715e88a803f7edbce0bff", size = 19572 }, +] + +[[package]] +name = "mako" +version = "1.3.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/62/4f/ddb1965901bc388958db9f0c991255b2c469349a741ae8c9cd8a562d70a6/mako-1.3.9.tar.gz", hash = "sha256:b5d65ff3462870feec922dbccf38f6efb44e5714d7b593a656be86663d8600ac", size = 392195 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/83/de0a49e7de540513f53ab5d2e105321dedeb08a8f5850f0208decf4390ec/Mako-1.3.9-py3-none-any.whl", hash = "sha256:95920acccb578427a9aa38e37a186b1e43156c87260d7ba18ca63aa4c7cbd3a1", size = 78456 }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357 }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393 }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732 }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866 }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964 }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977 }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366 }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091 }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065 }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514 }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353 }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392 }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984 }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120 }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032 }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057 }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359 }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306 }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094 }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521 }, + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348 }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149 }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118 }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993 }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178 }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319 }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352 }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097 }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601 }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274 }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352 }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122 }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085 }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978 }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208 }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357 }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344 }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101 }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603 }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510 }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486 }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480 }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914 }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796 }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473 }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114 }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098 }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208 }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739 }, +] + +[[package]] +name = "mock" +version = "5.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/07/8c/14c2ae915e5f9dca5a22edd68b35be94400719ccfa068a03e0fb63d0f6f6/mock-5.2.0.tar.gz", hash = "sha256:4e460e818629b4b173f32d08bf30d3af8123afbb8e04bb5707a1fd4799e503f0", size = 92796 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/d9/617e6af809bf3a1d468e0d58c3997b1dc219a9a9202e650d30c2fc85d481/mock-5.2.0-py3-none-any.whl", hash = "sha256:7ba87f72ca0e915175596069dbbcc7c75af7b5e9b9bc107ad6349ede0819982f", size = 31617 }, +] + +[[package]] +name = "notario" +version = "0.0.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/88/43/7ba8c182d832f4cadb2ddeed8d1d3a21da7be4b88c1ddb8eaf0aadee37a2/notario-0.0.16.tar.gz", hash = "sha256:71c7d1254857c0832b928979ae47be15118724b83b5e7bb2e5fe0acbdc652f78", size = 26321 } + +[[package]] +name = "packaging" +version = "24.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 }, +] + +[[package]] +name = "pecan" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mako" }, + { name = "setuptools" }, + { name = "webob" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/c6/e5f3cc7afef5951e03b287c58dc2f8417242f2ffad423b62db77099e9b52/pecan-1.6.0.tar.gz", hash = "sha256:5fd4469583eed2ded37b4d10a470e11a5de3f3c963dc87984e772e25c56fed3e", size = 123756 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/88/cd6606060fd0a260bd372bb19b07dc92435b7a127329733d0230a142f928/pecan-1.6.0-py3-none-any.whl", hash = "sha256:f23e79b0a3bfc6bacef494b9aaeacc7f1896a55de00b2aae62372e6dcd371aeb", size = 145739 }, +] + +[[package]] +name = "pecan-notario" +version = "0.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "notario" }, + { name = "pecan" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/27/95/acc1c292afd73065d9433092247ec3a9edeccd3df4069236ba11f51ccea1/pecan-notario-0.0.3.tar.gz", hash = "sha256:92114160ee39832d9dd523f1859ea9ba7d8260a0972eb5140fda9cfc39fd8536", size = 5348 } + +[[package]] +name = "pika" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/db/db/d4102f356af18f316c67f2cead8ece307f731dd63140e2c71f170ddacf9b/pika-1.3.2.tar.gz", hash = "sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f", size = 145029 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/f3/f412836ec714d36f0f4ab581b84c491e3f42c6b5b97a6c6ed1817f3c16d0/pika-1.3.2-py3-none-any.whl", hash = "sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f", size = 155415 }, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 }, +] + +[[package]] +name = "psycopg2-binary" +version = "2.9.9" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/07/e720e53bfab016ebcc34241695ccc06a9e3d91ba19b40ca81317afbdc440/psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c", size = 384973 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/7c/6aaf8c3cb05d86d2c3f407b95bac0c71a43f2718e38c1091972aacb5e1b2/psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202", size = 2822503 }, + { url = "https://files.pythonhosted.org/packages/72/3d/acab427845198794aafd963dd073ee35810e2c52606e8a28c12db39821fb/psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7", size = 2552645 }, + { url = "https://files.pythonhosted.org/packages/ed/be/6c787962d706e55a528ef1693dd7251de657ae60e4d9d767ed61e8e2975c/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b", size = 2850980 }, + { url = "https://files.pythonhosted.org/packages/83/50/a054076c6358753661cd1da59f4dabc03e83d51690371f3fd1edb9e2cf72/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9", size = 3080543 }, + { url = "https://files.pythonhosted.org/packages/9c/02/826dc5cdfc9515423ec912ba00cc2e4eb09f69e0339b177c9c742f2a09a2/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84", size = 3264316 }, + { url = "https://files.pythonhosted.org/packages/bc/0d/486e3fa27f39a00168abfcf14a3d8444f437f4b755cc34316da1124f293d/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e", size = 3019508 }, + { url = "https://files.pythonhosted.org/packages/41/af/bce37630c525d2b9cf93f930110fc98616d6aca308d59b833b83b3a38176/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98", size = 2355821 }, + { url = "https://files.pythonhosted.org/packages/3b/76/e46dae1b2273814ef80231f86d59cadf94ec36fd757045ed713c5b75cde7/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245", size = 2534855 }, + { url = "https://files.pythonhosted.org/packages/0e/6d/e97245eabff29d7c2de5fc1fc17cf7ef427beee93d20a5ae114c6e6718bd/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e", size = 2486614 }, + { url = "https://files.pythonhosted.org/packages/70/a7/2cd2c9d5e23b556c11e3b7da41895808d9b056f8f34f50de4375a35b4951/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f", size = 2454928 }, + { url = "https://files.pythonhosted.org/packages/63/41/815d19767e2adb1a585213b801c954f46102f305c352c4a4f96287342d44/psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682", size = 1025249 }, + { url = "https://files.pythonhosted.org/packages/5e/4c/9233e0e206634a5387f3ab40f334a5325fb8bef2ca4e12ee7dbdeaf96afc/psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0", size = 1163645 }, + { url = "https://files.pythonhosted.org/packages/a5/ac/702d300f3df169b9d0cbef0340d9f34a78bc18dc2dbafbcb39ff0f165cf8/psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26", size = 2822581 }, + { url = "https://files.pythonhosted.org/packages/7a/1f/a6cf0cdf944253f7c45d90fbc876cc8bed5cc9942349306245715c0d88d6/psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f", size = 2552633 }, + { url = "https://files.pythonhosted.org/packages/81/0b/3adf561107c865928455891156d1dde5325253f7f4316fe56cd2c3f73570/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2", size = 2851075 }, + { url = "https://files.pythonhosted.org/packages/f7/98/c2fedcbf0a9607519a010dcf88571138b2251062dbde3610cdba5ba1eee1/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0", size = 3080509 }, + { url = "https://files.pythonhosted.org/packages/c2/05/81e8bc7fca95574c9323e487d9ce1b58a4cfcc17f89b8fe843af46361211/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53", size = 3264303 }, + { url = "https://files.pythonhosted.org/packages/ce/85/62825cabc6aad53104b7b6d12eb2ad74737d268630032d07b74d4444cb72/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be", size = 3019515 }, + { url = "https://files.pythonhosted.org/packages/e9/b0/9ca2b8e01a0912c9a14234fd5df7a241a1e44778c5797bf4b8eaa8dc3d3a/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27", size = 2355892 }, + { url = "https://files.pythonhosted.org/packages/73/17/ba28bb0022db5e2015a82d2df1c4b0d419c37fa07a588b3aff3adc4939f6/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359", size = 2534903 }, + { url = "https://files.pythonhosted.org/packages/3b/92/b463556409cdc12791cd8b1dae0072bf8efe817ef68b7ea3d9cf7d0e5656/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2", size = 2486597 }, + { url = "https://files.pythonhosted.org/packages/92/57/96576e07132d7f7a1ac1df939575e6fdd8951aea337ee152b586bb51a971/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc", size = 2454908 }, + { url = "https://files.pythonhosted.org/packages/7c/ae/cedd56e1f4a2b0e37213283caf3733a875c4c76f3372241e19c0d2a87355/psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d", size = 1024240 }, + { url = "https://files.pythonhosted.org/packages/25/1f/7ae31759142999a8d06b3e250c1346c4abcdcada8fa884376775dc1de686/psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417", size = 1163655 }, + { url = "https://files.pythonhosted.org/packages/a7/d0/5f2db14e7b53552276ab613399a83f83f85b173a862d3f20580bc7231139/psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf", size = 2823784 }, + { url = "https://files.pythonhosted.org/packages/18/ca/da384fd47233e300e3e485c90e7aab5d7def896d1281239f75901faf87d4/psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d", size = 2553308 }, + { url = "https://files.pythonhosted.org/packages/50/66/fa53d2d3d92f6e1ef469d92afc6a4fe3f6e8a9a04b687aa28fb1f1d954ee/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212", size = 2851283 }, + { url = "https://files.pythonhosted.org/packages/04/37/2429360ac5547378202db14eec0dde76edbe1f6627df5a43c7e164922859/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493", size = 3081839 }, + { url = "https://files.pythonhosted.org/packages/62/2a/c0530b59d7e0d09824bc2102ecdcec0456b8ca4d47c0caa82e86fce3ed4c/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996", size = 3264488 }, + { url = "https://files.pythonhosted.org/packages/19/57/9f172b900795ea37246c78b5f52e00f4779984370855b3e161600156906d/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119", size = 3020700 }, + { url = "https://files.pythonhosted.org/packages/94/68/1176fc14ea76861b7b8360be5176e87fb20d5091b137c76570eb4e237324/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba", size = 2355968 }, + { url = "https://files.pythonhosted.org/packages/70/bb/aec2646a705a09079d008ce88073401cd61fc9b04f92af3eb282caa3a2ec/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07", size = 2536101 }, + { url = "https://files.pythonhosted.org/packages/14/33/12818c157e333cb9d9e6753d1b2463b6f60dbc1fade115f8e4dc5c52cac4/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb", size = 2487064 }, + { url = "https://files.pythonhosted.org/packages/56/a2/7851c68fe8768f3c9c246198b6356ee3e4a8a7f6820cc798443faada3400/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe", size = 2456257 }, + { url = "https://files.pythonhosted.org/packages/6f/ee/3ba07c6dc7c3294e717e94720da1597aedc82a10b1b180203ce183d4631a/psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93", size = 1024709 }, + { url = "https://files.pythonhosted.org/packages/7b/08/9c66c269b0d417a0af9fb969535f0371b8c538633535a7a6a5ca3f9231e2/psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab", size = 1163864 }, +] + +[[package]] +name = "pytest" +version = "8.3.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 }, +] + +[[package]] +name = "requests" +version = "2.32.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928 }, +] + +[[package]] +name = "setuptools" +version = "78.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/5a/0db4da3bc908df06e5efae42b44e75c81dd52716e10192ff36d0c1c8e379/setuptools-78.1.0.tar.gz", hash = "sha256:18fd474d4a82a5f83dac888df697af65afa82dec7323d09c3e37d1f14288da54", size = 1367827 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/21/f43f0a1fa8b06b32812e0975981f4677d28e0f3271601dc88ac5a5b83220/setuptools-78.1.0-py3-none-any.whl", hash = "sha256:3e386e96793c8702ae83d17b853fb93d3e09ef82ec62722e61da5cd22376dcd8", size = 1256108 }, +] + +[[package]] +name = "shaman" +version = "0.1" +source = { editable = "." } +dependencies = [ + { name = "jinja2" }, + { name = "pecan" }, + { name = "pecan-notario" }, + { name = "pika" }, + { name = "psycopg2-binary" }, + { name = "requests" }, + { name = "sqlalchemy" }, +] + +[package.optional-dependencies] +test = [ + { name = "mock" }, + { name = "pytest" }, + { name = "webtest" }, +] + +[package.metadata] +requires-dist = [ + { name = "jinja2" }, + { name = "mock", marker = "extra == 'test'" }, + { name = "pecan" }, + { name = "pecan-notario" }, + { name = "pika" }, + { name = "psycopg2-binary", specifier = "==2.9.9" }, + { name = "pytest", marker = "extra == 'test'" }, + { name = "requests" }, + { name = "sqlalchemy", specifier = "==1.4.53" }, + { name = "webtest", marker = "extra == 'test'" }, +] +provides-extras = ["test"] + +[[package]] +name = "soupsieve" +version = "2.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d7/ce/fbaeed4f9fb8b2daa961f90591662df6a86c1abf25c548329a86920aedfb/soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb", size = 101569 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/c2/fe97d779f3ef3b15f05c94a2f1e3d21732574ed441687474db9d342a7315/soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9", size = 36186 }, +] + +[[package]] +name = "sqlalchemy" +version = "1.4.53" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "platform_machine == 'AMD64' or platform_machine == 'WIN32' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'ppc64le' or platform_machine == 'win32' or platform_machine == 'x86_64'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e8/f1/40d71bba877e1c92d5995de3605d6256be1cc148d2ca0475812f156d7a58/SQLAlchemy-1.4.53.tar.gz", hash = "sha256:5e6ab710c4c064755fd92d1a417bef360228a19bdf0eee32b03aa0f5f8e9fe0d", size = 8468030 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/35/1ce283cafd9c51551a7512f2c9d170a9154336e2d815665a36e9d711c79b/SQLAlchemy-1.4.53-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:b61ac5457d91b5629a3dea2b258deb4cdd35ac8f6fa2031d2b9b2fff5b3396da", size = 1573202 }, + { url = "https://files.pythonhosted.org/packages/ed/0f/9342b6d383fa3e802dca447c41593b346f3e15cd651968ccd75a0ad9d5b0/SQLAlchemy-1.4.53-cp310-cp310-manylinux1_x86_64.manylinux2010_x86_64.manylinux_2_12_x86_64.manylinux_2_5_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1a96aa8d425047551676b0e178ddb0683421e78eda879ab55775128b2e612cae", size = 1638829 }, + { url = "https://files.pythonhosted.org/packages/af/6f/9f53c1e90461eeba463f648fd00edd1114ce6cdf4ca49858e333027bf779/SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e10ac36f0b994235c13388b39598bf27219ec8bdea5be99bdac612b01cbe525", size = 1627295 }, + { url = "https://files.pythonhosted.org/packages/31/ca/8e4bd3f82823b61100f9316f2b7b3d4250d46fe9bed6410df73928a0b790/SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:437592b341a3229dd0443c9c803b0bf0a466f8f539014fef6cdb9c06b7edb7f9", size = 1638822 }, + { url = "https://files.pythonhosted.org/packages/61/f5/de8dbe9cfb384ef3e5368d817107704ba9a824abe1a68355fe3d2e26d681/SQLAlchemy-1.4.53-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:784272ceb5eb71421fea9568749bcbe8bd019261a0e2e710a7efa76057af2499", size = 1638821 }, + { url = "https://files.pythonhosted.org/packages/4f/44/a66615f089bfb399003ee0ae77f3859a93c281f3adffa4cd32d3f1e1410d/SQLAlchemy-1.4.53-cp310-cp310-win32.whl", hash = "sha256:122d7b5722df1a24402c6748bbb04687ef981493bb559d0cc0beffe722e0e6ed", size = 1591362 }, + { url = "https://files.pythonhosted.org/packages/7d/a0/9c1b1ea657eae9f153de4bc37c716de2831a5a22b9bc3e35eb04d92ab352/SQLAlchemy-1.4.53-cp310-cp310-win_amd64.whl", hash = "sha256:4604d42b2abccba266d3f5bbe883684b5df93e74054024c70d3fbb5eea45e530", size = 1593269 }, + { url = "https://files.pythonhosted.org/packages/d5/99/8f26e70e6356770a50eecaaa982235fe6dda29bb888a04d318cb3bdb7196/SQLAlchemy-1.4.53-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:fb8e15dfa47f5de11ab073e12aadd6b502cfb7ac4bafd18bd18cfd1c7d13dbbc", size = 1589039 }, + { url = "https://files.pythonhosted.org/packages/0c/c8/2629831d5835e2cc29f2c21d361fb6230dc6c8c00f44d6eef70e94c40e43/SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc8be4df55e8fde3006d9cb1f6b3df2ba26db613855dc4df2c0fcd5ec15cb3b7", size = 1629404 }, + { url = "https://files.pythonhosted.org/packages/d4/73/febc853519404d2c025e36c471eb320288306bc129842fd23e03be6affff/SQLAlchemy-1.4.53-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86b11640251f9a9789fd96cd6e5d176b1c230230c70ad40299bcbcc568451b4c", size = 1627489 }, + { url = "https://files.pythonhosted.org/packages/1c/82/9c504ffaaf6528d0e6e883793d95e0075e891013bb0561567c7d01f62c69/SQLAlchemy-1.4.53-cp311-cp311-win32.whl", hash = "sha256:cd534c716f86bdf95b7b984a34ee278c91d1b1d7d183e7e5ff878600b1696046", size = 1591359 }, + { url = "https://files.pythonhosted.org/packages/3b/c6/832d6f2846fe7caa2fee2687a99f1ffe5719a921ff557b93634380c8e976/SQLAlchemy-1.4.53-cp311-cp311-win_amd64.whl", hash = "sha256:6dd06572872ca13ef5a90306a3e5af787498ddaa17fb00109b1243642646cd69", size = 1593272 }, + { url = "https://files.pythonhosted.org/packages/75/f8/6e04c212f8b495c9ec324a5079a57e0d97b49324a14c393388cf8fa100bb/SQLAlchemy-1.4.53-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:2774c24c405136c3ef472e2352bdca7330659d481fbf2283f996c0ef9eb90f22", size = 1589715 }, + { url = "https://files.pythonhosted.org/packages/3a/c0/2f4e45ce194636098ca2a810ddd1a7bdfee6513de8fa0796b45ca5ef5461/SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68a614765197b3d13a730d631a78c3bb9b3b72ba58ed7ab295d58d517464e315", size = 1630006 }, + { url = "https://files.pythonhosted.org/packages/9c/85/27d94ae4b18d97d151b201aa68176209bcd03f6932944b0354e6cd47fb6d/SQLAlchemy-1.4.53-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d13d4dfbc6e52363886b47cf02cf68c5d2a37c468626694dc210d7e97d4ad330", size = 1629076 }, + { url = "https://files.pythonhosted.org/packages/f2/7d/50ff5f68bfd4055032b9f3396468c59af5248f7606fce4fa4fcb4d795ecf/SQLAlchemy-1.4.53-cp312-cp312-win32.whl", hash = "sha256:197065b91456574d70b6459bfa62bc0b52a4960a29ef923c375ec427274a3e05", size = 1591762 }, + { url = "https://files.pythonhosted.org/packages/cf/a9/45cf3395769853bf7d2a84848f8af6038c572c7b2755afe54d894d76465a/SQLAlchemy-1.4.53-cp312-cp312-win_amd64.whl", hash = "sha256:421306c4b936b0271a3ce2dc074928d5ece4a36f9c482daa5770f44ecfc3a883", size = 1593560 }, +] + +[[package]] +name = "tomli" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077 }, + { url = "https://files.pythonhosted.org/packages/c7/16/51ae563a8615d472fdbffc43a3f3d46588c264ac4f024f63f01283becfbb/tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6", size = 123429 }, + { url = "https://files.pythonhosted.org/packages/f1/dd/4f6cd1e7b160041db83c694abc78e100473c15d54620083dbd5aae7b990e/tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a", size = 226067 }, + { url = "https://files.pythonhosted.org/packages/a9/6b/c54ede5dc70d648cc6361eaf429304b02f2871a345bbdd51e993d6cdf550/tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee", size = 236030 }, + { url = "https://files.pythonhosted.org/packages/1f/47/999514fa49cfaf7a92c805a86c3c43f4215621855d151b61c602abb38091/tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e", size = 240898 }, + { url = "https://files.pythonhosted.org/packages/73/41/0a01279a7ae09ee1573b423318e7934674ce06eb33f50936655071d81a24/tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4", size = 229894 }, + { url = "https://files.pythonhosted.org/packages/55/18/5d8bc5b0a0362311ce4d18830a5d28943667599a60d20118074ea1b01bb7/tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106", size = 245319 }, + { url = "https://files.pythonhosted.org/packages/92/a3/7ade0576d17f3cdf5ff44d61390d4b3febb8a9fc2b480c75c47ea048c646/tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8", size = 238273 }, + { url = "https://files.pythonhosted.org/packages/72/6f/fa64ef058ac1446a1e51110c375339b3ec6be245af9d14c87c4a6412dd32/tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff", size = 98310 }, + { url = "https://files.pythonhosted.org/packages/6a/1c/4a2dcde4a51b81be3530565e92eda625d94dafb46dbeb15069df4caffc34/tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b", size = 108309 }, + { url = "https://files.pythonhosted.org/packages/52/e1/f8af4c2fcde17500422858155aeb0d7e93477a0d59a98e56cbfe75070fd0/tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea", size = 132762 }, + { url = "https://files.pythonhosted.org/packages/03/b8/152c68bb84fc00396b83e7bbddd5ec0bd3dd409db4195e2a9b3e398ad2e3/tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8", size = 123453 }, + { url = "https://files.pythonhosted.org/packages/c8/d6/fc9267af9166f79ac528ff7e8c55c8181ded34eb4b0e93daa767b8841573/tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192", size = 233486 }, + { url = "https://files.pythonhosted.org/packages/5c/51/51c3f2884d7bab89af25f678447ea7d297b53b5a3b5730a7cb2ef6069f07/tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222", size = 242349 }, + { url = "https://files.pythonhosted.org/packages/ab/df/bfa89627d13a5cc22402e441e8a931ef2108403db390ff3345c05253935e/tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77", size = 252159 }, + { url = "https://files.pythonhosted.org/packages/9e/6e/fa2b916dced65763a5168c6ccb91066f7639bdc88b48adda990db10c8c0b/tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6", size = 237243 }, + { url = "https://files.pythonhosted.org/packages/b4/04/885d3b1f650e1153cbb93a6a9782c58a972b94ea4483ae4ac5cedd5e4a09/tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd", size = 259645 }, + { url = "https://files.pythonhosted.org/packages/9c/de/6b432d66e986e501586da298e28ebeefd3edc2c780f3ad73d22566034239/tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e", size = 244584 }, + { url = "https://files.pythonhosted.org/packages/1c/9a/47c0449b98e6e7d1be6cbac02f93dd79003234ddc4aaab6ba07a9a7482e2/tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98", size = 98875 }, + { url = "https://files.pythonhosted.org/packages/ef/60/9b9638f081c6f1261e2688bd487625cd1e660d0a85bd469e91d8db969734/tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4", size = 109418 }, + { url = "https://files.pythonhosted.org/packages/04/90/2ee5f2e0362cb8a0b6499dc44f4d7d48f8fff06d28ba46e6f1eaa61a1388/tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7", size = 132708 }, + { url = "https://files.pythonhosted.org/packages/c0/ec/46b4108816de6b385141f082ba99e315501ccd0a2ea23db4a100dd3990ea/tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c", size = 123582 }, + { url = "https://files.pythonhosted.org/packages/a0/bd/b470466d0137b37b68d24556c38a0cc819e8febe392d5b199dcd7f578365/tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13", size = 232543 }, + { url = "https://files.pythonhosted.org/packages/d9/e5/82e80ff3b751373f7cead2815bcbe2d51c895b3c990686741a8e56ec42ab/tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281", size = 241691 }, + { url = "https://files.pythonhosted.org/packages/05/7e/2a110bc2713557d6a1bfb06af23dd01e7dde52b6ee7dadc589868f9abfac/tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272", size = 251170 }, + { url = "https://files.pythonhosted.org/packages/64/7b/22d713946efe00e0adbcdfd6d1aa119ae03fd0b60ebed51ebb3fa9f5a2e5/tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140", size = 236530 }, + { url = "https://files.pythonhosted.org/packages/38/31/3a76f67da4b0cf37b742ca76beaf819dca0ebef26d78fc794a576e08accf/tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2", size = 258666 }, + { url = "https://files.pythonhosted.org/packages/07/10/5af1293da642aded87e8a988753945d0cf7e00a9452d3911dd3bb354c9e2/tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744", size = 243954 }, + { url = "https://files.pythonhosted.org/packages/5b/b9/1ed31d167be802da0fc95020d04cd27b7d7065cc6fbefdd2f9186f60d7bd/tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec", size = 98724 }, + { url = "https://files.pythonhosted.org/packages/c7/32/b0963458706accd9afcfeb867c0f9175a741bf7b19cd424230714d722198/tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69", size = 109383 }, + { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257 }, +] + +[[package]] +name = "typing-extensions" +version = "4.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0e/3e/b00a62db91a83fff600de219b6ea9908e6918664899a2d85db222f4fbf19/typing_extensions-4.13.0.tar.gz", hash = "sha256:0a4ac55a5820789d87e297727d229866c9650f6521b64206413c4fbada24d95b", size = 106520 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/86/39b65d676ec5732de17b7e3c476e45bb80ec64eb50737a8dce1a4178aba1/typing_extensions-4.13.0-py3-none-any.whl", hash = "sha256:c8dd92cc0d6425a97c18fbb9d1954e5ff92c1ca881a309c45f06ebc0b79058e5", size = 45683 }, +] + +[[package]] +name = "urllib3" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369 }, +] + +[[package]] +name = "waitress" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232 }, +] + +[[package]] +name = "webob" +version = "1.8.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "legacy-cgi", marker = "python_full_version >= '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/85/0b/1732085540b01f65e4e7999e15864fe14cd18b12a95731a43fd6fd11b26a/webob-1.8.9.tar.gz", hash = "sha256:ad6078e2edb6766d1334ec3dee072ac6a7f95b1e32ce10def8ff7f0f02d56589", size = 279775 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/bd/c336448be43d40be28e71f2e0f3caf7ccb28e2755c58f4c02c065bfe3e8e/WebOb-1.8.9-py2.py3-none-any.whl", hash = "sha256:45e34c58ed0c7e2ecd238ffd34432487ff13d9ad459ddfd77895e67abba7c1f9", size = 115364 }, +] + +[[package]] +name = "webtest" +version = "3.0.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "beautifulsoup4" }, + { name = "waitress" }, + { name = "webob" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/26/c5/b25980d591b111f3898c27b140bc30977794157522a8da91f5bbb5de99b7/webtest-3.0.4.tar.gz", hash = "sha256:94778d19a37e5abd7388dad4d93874410ecced53a1739a8e5ff2dbcba1cfc0c4", size = 79395 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/69/df392f611d46b1ca32e829ba7db1a01d147875cfd51942c39c3f9dc1e48d/WebTest-3.0.4-py3-none-any.whl", hash = "sha256:5b3d8c69ac9057f17750ed5b45320a411423c2b4196bec6450961be98b03d8c1", size = 32149 }, +] From ec64982332a9d2811a68ef93a529b51b400d8f6f Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Tue, 1 Apr 2025 12:41:51 -0600 Subject: [PATCH 03/10] Bump psycopg2-binary version Signed-off-by: Zack Cerza --- pyproject.toml | 2 +- requirements.txt | 87 +++++++++++++++++++++++++--------------------- uv.lock | 89 +++++++++++++++++++++++++++--------------------- 3 files changed, 100 insertions(+), 78 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 826e047..f02cb82 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ requires-python = ">=3.10" dependencies = [ "pecan", "sqlalchemy==1.4.53", - "psycopg2-binary==2.9.9", + "psycopg2-binary==2.9.10", "pecan-notario", "requests", "jinja2", diff --git a/requirements.txt b/requirements.txt index 984ccfc..6e5eae0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -178,44 +178,55 @@ pecan-notario==0.0.3 \ pika==1.3.2 \ --hash=sha256:0779a7c1fafd805672796085560d290213a465e4f6f76a6fb19e378d8041a14f \ --hash=sha256:b2a327ddddf8570b4965b3576ac77091b850262d34ce8c1d8cb4e4146aa4145f -psycopg2-binary==2.9.9 \ - --hash=sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e \ - --hash=sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84 \ - --hash=sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2 \ - --hash=sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f \ - --hash=sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493 \ - --hash=sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996 \ - --hash=sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682 \ - --hash=sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe \ - --hash=sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93 \ - --hash=sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119 \ - --hash=sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b \ - --hash=sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2 \ - --hash=sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc \ - --hash=sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c \ - --hash=sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab \ - --hash=sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9 \ - --hash=sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf \ - --hash=sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0 \ - --hash=sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f \ - --hash=sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212 \ - --hash=sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb \ - --hash=sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be \ - --hash=sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d \ - --hash=sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245 \ - --hash=sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27 \ - --hash=sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417 \ - --hash=sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359 \ - --hash=sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202 \ - --hash=sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0 \ - --hash=sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7 \ - --hash=sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba \ - --hash=sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07 \ - --hash=sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98 \ - --hash=sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d \ - --hash=sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e \ - --hash=sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26 \ - --hash=sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53 +psycopg2-binary==2.9.10 \ + --hash=sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff \ + --hash=sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f \ + --hash=sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5 \ + --hash=sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0 \ + --hash=sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c \ + --hash=sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341 \ + --hash=sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f \ + --hash=sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7 \ + --hash=sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d \ + --hash=sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007 \ + --hash=sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142 \ + --hash=sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92 \ + --hash=sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb \ + --hash=sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5 \ + --hash=sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1 \ + --hash=sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68 \ + --hash=sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73 \ + --hash=sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1 \ + --hash=sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53 \ + --hash=sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d \ + --hash=sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906 \ + --hash=sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0 \ + --hash=sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2 \ + --hash=sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a \ + --hash=sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b \ + --hash=sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7 \ + --hash=sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f \ + --hash=sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526 \ + --hash=sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4 \ + --hash=sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e \ + --hash=sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673 \ + --hash=sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0 \ + --hash=sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e \ + --hash=sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a \ + --hash=sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c \ + --hash=sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909 \ + --hash=sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47 \ + --hash=sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00 \ + --hash=sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb \ + --hash=sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539 \ + --hash=sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b \ + --hash=sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5 \ + --hash=sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64 \ + --hash=sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392 \ + --hash=sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4 \ + --hash=sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1 \ + --hash=sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1 \ + --hash=sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567 requests==2.32.3 \ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 diff --git a/uv.lock b/uv.lock index a844b4f..4ae67d1 100644 --- a/uv.lock +++ b/uv.lock @@ -335,46 +335,57 @@ wheels = [ [[package]] name = "psycopg2-binary" -version = "2.9.9" +version = "2.9.10" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/07/e720e53bfab016ebcc34241695ccc06a9e3d91ba19b40ca81317afbdc440/psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c", size = 384973 } +sdist = { url = "https://files.pythonhosted.org/packages/cb/0e/bdc8274dc0585090b4e3432267d7be4dfbfd8971c0fa59167c711105a6bf/psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2", size = 385764 } wheels = [ - { url = "https://files.pythonhosted.org/packages/0a/7c/6aaf8c3cb05d86d2c3f407b95bac0c71a43f2718e38c1091972aacb5e1b2/psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202", size = 2822503 }, - { url = "https://files.pythonhosted.org/packages/72/3d/acab427845198794aafd963dd073ee35810e2c52606e8a28c12db39821fb/psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7", size = 2552645 }, - { url = "https://files.pythonhosted.org/packages/ed/be/6c787962d706e55a528ef1693dd7251de657ae60e4d9d767ed61e8e2975c/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b", size = 2850980 }, - { url = "https://files.pythonhosted.org/packages/83/50/a054076c6358753661cd1da59f4dabc03e83d51690371f3fd1edb9e2cf72/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9", size = 3080543 }, - { url = "https://files.pythonhosted.org/packages/9c/02/826dc5cdfc9515423ec912ba00cc2e4eb09f69e0339b177c9c742f2a09a2/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84", size = 3264316 }, - { url = "https://files.pythonhosted.org/packages/bc/0d/486e3fa27f39a00168abfcf14a3d8444f437f4b755cc34316da1124f293d/psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e", size = 3019508 }, - { url = "https://files.pythonhosted.org/packages/41/af/bce37630c525d2b9cf93f930110fc98616d6aca308d59b833b83b3a38176/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98", size = 2355821 }, - { url = "https://files.pythonhosted.org/packages/3b/76/e46dae1b2273814ef80231f86d59cadf94ec36fd757045ed713c5b75cde7/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245", size = 2534855 }, - { url = "https://files.pythonhosted.org/packages/0e/6d/e97245eabff29d7c2de5fc1fc17cf7ef427beee93d20a5ae114c6e6718bd/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e", size = 2486614 }, - { url = "https://files.pythonhosted.org/packages/70/a7/2cd2c9d5e23b556c11e3b7da41895808d9b056f8f34f50de4375a35b4951/psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f", size = 2454928 }, - { url = "https://files.pythonhosted.org/packages/63/41/815d19767e2adb1a585213b801c954f46102f305c352c4a4f96287342d44/psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682", size = 1025249 }, - { url = "https://files.pythonhosted.org/packages/5e/4c/9233e0e206634a5387f3ab40f334a5325fb8bef2ca4e12ee7dbdeaf96afc/psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0", size = 1163645 }, - { url = "https://files.pythonhosted.org/packages/a5/ac/702d300f3df169b9d0cbef0340d9f34a78bc18dc2dbafbcb39ff0f165cf8/psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26", size = 2822581 }, - { url = "https://files.pythonhosted.org/packages/7a/1f/a6cf0cdf944253f7c45d90fbc876cc8bed5cc9942349306245715c0d88d6/psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f", size = 2552633 }, - { url = "https://files.pythonhosted.org/packages/81/0b/3adf561107c865928455891156d1dde5325253f7f4316fe56cd2c3f73570/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2", size = 2851075 }, - { url = "https://files.pythonhosted.org/packages/f7/98/c2fedcbf0a9607519a010dcf88571138b2251062dbde3610cdba5ba1eee1/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0", size = 3080509 }, - { url = "https://files.pythonhosted.org/packages/c2/05/81e8bc7fca95574c9323e487d9ce1b58a4cfcc17f89b8fe843af46361211/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53", size = 3264303 }, - { url = "https://files.pythonhosted.org/packages/ce/85/62825cabc6aad53104b7b6d12eb2ad74737d268630032d07b74d4444cb72/psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be", size = 3019515 }, - { url = "https://files.pythonhosted.org/packages/e9/b0/9ca2b8e01a0912c9a14234fd5df7a241a1e44778c5797bf4b8eaa8dc3d3a/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27", size = 2355892 }, - { url = "https://files.pythonhosted.org/packages/73/17/ba28bb0022db5e2015a82d2df1c4b0d419c37fa07a588b3aff3adc4939f6/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359", size = 2534903 }, - { url = "https://files.pythonhosted.org/packages/3b/92/b463556409cdc12791cd8b1dae0072bf8efe817ef68b7ea3d9cf7d0e5656/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2", size = 2486597 }, - { url = "https://files.pythonhosted.org/packages/92/57/96576e07132d7f7a1ac1df939575e6fdd8951aea337ee152b586bb51a971/psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc", size = 2454908 }, - { url = "https://files.pythonhosted.org/packages/7c/ae/cedd56e1f4a2b0e37213283caf3733a875c4c76f3372241e19c0d2a87355/psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d", size = 1024240 }, - { url = "https://files.pythonhosted.org/packages/25/1f/7ae31759142999a8d06b3e250c1346c4abcdcada8fa884376775dc1de686/psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417", size = 1163655 }, - { url = "https://files.pythonhosted.org/packages/a7/d0/5f2db14e7b53552276ab613399a83f83f85b173a862d3f20580bc7231139/psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf", size = 2823784 }, - { url = "https://files.pythonhosted.org/packages/18/ca/da384fd47233e300e3e485c90e7aab5d7def896d1281239f75901faf87d4/psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d", size = 2553308 }, - { url = "https://files.pythonhosted.org/packages/50/66/fa53d2d3d92f6e1ef469d92afc6a4fe3f6e8a9a04b687aa28fb1f1d954ee/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212", size = 2851283 }, - { url = "https://files.pythonhosted.org/packages/04/37/2429360ac5547378202db14eec0dde76edbe1f6627df5a43c7e164922859/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493", size = 3081839 }, - { url = "https://files.pythonhosted.org/packages/62/2a/c0530b59d7e0d09824bc2102ecdcec0456b8ca4d47c0caa82e86fce3ed4c/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996", size = 3264488 }, - { url = "https://files.pythonhosted.org/packages/19/57/9f172b900795ea37246c78b5f52e00f4779984370855b3e161600156906d/psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119", size = 3020700 }, - { url = "https://files.pythonhosted.org/packages/94/68/1176fc14ea76861b7b8360be5176e87fb20d5091b137c76570eb4e237324/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba", size = 2355968 }, - { url = "https://files.pythonhosted.org/packages/70/bb/aec2646a705a09079d008ce88073401cd61fc9b04f92af3eb282caa3a2ec/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07", size = 2536101 }, - { url = "https://files.pythonhosted.org/packages/14/33/12818c157e333cb9d9e6753d1b2463b6f60dbc1fade115f8e4dc5c52cac4/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb", size = 2487064 }, - { url = "https://files.pythonhosted.org/packages/56/a2/7851c68fe8768f3c9c246198b6356ee3e4a8a7f6820cc798443faada3400/psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe", size = 2456257 }, - { url = "https://files.pythonhosted.org/packages/6f/ee/3ba07c6dc7c3294e717e94720da1597aedc82a10b1b180203ce183d4631a/psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93", size = 1024709 }, - { url = "https://files.pythonhosted.org/packages/7b/08/9c66c269b0d417a0af9fb969535f0371b8c538633535a7a6a5ca3f9231e2/psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab", size = 1163864 }, + { url = "https://files.pythonhosted.org/packages/7a/81/331257dbf2801cdb82105306042f7a1637cc752f65f2bb688188e0de5f0b/psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f", size = 3043397 }, + { url = "https://files.pythonhosted.org/packages/e7/9a/7f4f2f031010bbfe6a02b4a15c01e12eb6b9b7b358ab33229f28baadbfc1/psycopg2_binary-2.9.10-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:3e9c76f0ac6f92ecfc79516a8034a544926430f7b080ec5a0537bca389ee0906", size = 3274806 }, + { url = "https://files.pythonhosted.org/packages/e5/57/8ddd4b374fa811a0b0a0f49b6abad1cde9cb34df73ea3348cc283fcd70b4/psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ad26b467a405c798aaa1458ba09d7e2b6e5f96b1ce0ac15d82fd9f95dc38a92", size = 2851361 }, + { url = "https://files.pythonhosted.org/packages/f9/66/d1e52c20d283f1f3a8e7e5c1e06851d432f123ef57b13043b4f9b21ffa1f/psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:270934a475a0e4b6925b5f804e3809dd5f90f8613621d062848dd82f9cd62007", size = 3080836 }, + { url = "https://files.pythonhosted.org/packages/a0/cb/592d44a9546aba78f8a1249021fe7c59d3afb8a0ba51434d6610cc3462b6/psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:48b338f08d93e7be4ab2b5f1dbe69dc5e9ef07170fe1f86514422076d9c010d0", size = 3264552 }, + { url = "https://files.pythonhosted.org/packages/64/33/c8548560b94b7617f203d7236d6cdf36fe1a5a3645600ada6efd79da946f/psycopg2_binary-2.9.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f4152f8f76d2023aac16285576a9ecd2b11a9895373a1f10fd9db54b3ff06b4", size = 3019789 }, + { url = "https://files.pythonhosted.org/packages/b0/0e/c2da0db5bea88a3be52307f88b75eec72c4de62814cbe9ee600c29c06334/psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:32581b3020c72d7a421009ee1c6bf4a131ef5f0a968fab2e2de0c9d2bb4577f1", size = 2871776 }, + { url = "https://files.pythonhosted.org/packages/15/d7/774afa1eadb787ddf41aab52d4c62785563e29949613c958955031408ae6/psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:2ce3e21dc3437b1d960521eca599d57408a695a0d3c26797ea0f72e834c7ffe5", size = 2820959 }, + { url = "https://files.pythonhosted.org/packages/5e/ed/440dc3f5991a8c6172a1cde44850ead0e483a375277a1aef7cfcec00af07/psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e984839e75e0b60cfe75e351db53d6db750b00de45644c5d1f7ee5d1f34a1ce5", size = 2919329 }, + { url = "https://files.pythonhosted.org/packages/03/be/2cc8f4282898306732d2ae7b7378ae14e8df3c1231b53579efa056aae887/psycopg2_binary-2.9.10-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3c4745a90b78e51d9ba06e2088a2fe0c693ae19cc8cb051ccda44e8df8a6eb53", size = 2957659 }, + { url = "https://files.pythonhosted.org/packages/d0/12/fb8e4f485d98c570e00dad5800e9a2349cfe0f71a767c856857160d343a5/psycopg2_binary-2.9.10-cp310-cp310-win32.whl", hash = "sha256:e5720a5d25e3b99cd0dc5c8a440570469ff82659bb09431c1439b92caf184d3b", size = 1024605 }, + { url = "https://files.pythonhosted.org/packages/22/4f/217cd2471ecf45d82905dd09085e049af8de6cfdc008b6663c3226dc1c98/psycopg2_binary-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:3c18f74eb4386bf35e92ab2354a12c17e5eb4d9798e4c0ad3a00783eae7cd9f1", size = 1163817 }, + { url = "https://files.pythonhosted.org/packages/9c/8f/9feb01291d0d7a0a4c6a6bab24094135c2b59c6a81943752f632c75896d6/psycopg2_binary-2.9.10-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:04392983d0bb89a8717772a193cfaac58871321e3ec69514e1c4e0d4957b5aff", size = 3043397 }, + { url = "https://files.pythonhosted.org/packages/15/30/346e4683532011561cd9c8dfeac6a8153dd96452fee0b12666058ab7893c/psycopg2_binary-2.9.10-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:1a6784f0ce3fec4edc64e985865c17778514325074adf5ad8f80636cd029ef7c", size = 3274806 }, + { url = "https://files.pythonhosted.org/packages/66/6e/4efebe76f76aee7ec99166b6c023ff8abdc4e183f7b70913d7c047701b79/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f86c56eeb91dc3135b3fd8a95dc7ae14c538a2f3ad77a19645cf55bab1799c", size = 2851370 }, + { url = "https://files.pythonhosted.org/packages/7f/fd/ff83313f86b50f7ca089b161b8e0a22bb3c319974096093cd50680433fdb/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b3d2491d4d78b6b14f76881905c7a8a8abcf974aad4a8a0b065273a0ed7a2cb", size = 3080780 }, + { url = "https://files.pythonhosted.org/packages/e6/c4/bfadd202dcda8333a7ccafdc51c541dbdfce7c2c7cda89fa2374455d795f/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2286791ececda3a723d1910441c793be44625d86d1a4e79942751197f4d30341", size = 3264583 }, + { url = "https://files.pythonhosted.org/packages/5d/f1/09f45ac25e704ac954862581f9f9ae21303cc5ded3d0b775532b407f0e90/psycopg2_binary-2.9.10-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:512d29bb12608891e349af6a0cccedce51677725a921c07dba6342beaf576f9a", size = 3019831 }, + { url = "https://files.pythonhosted.org/packages/9e/2e/9beaea078095cc558f215e38f647c7114987d9febfc25cb2beed7c3582a5/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5a507320c58903967ef7384355a4da7ff3f28132d679aeb23572753cbf2ec10b", size = 2871822 }, + { url = "https://files.pythonhosted.org/packages/01/9e/ef93c5d93f3dc9fc92786ffab39e323b9aed066ba59fdc34cf85e2722271/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6d4fa1079cab9018f4d0bd2db307beaa612b0d13ba73b5c6304b9fe2fb441ff7", size = 2820975 }, + { url = "https://files.pythonhosted.org/packages/a5/f0/049e9631e3268fe4c5a387f6fc27e267ebe199acf1bc1bc9cbde4bd6916c/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:851485a42dbb0bdc1edcdabdb8557c09c9655dfa2ca0460ff210522e073e319e", size = 2919320 }, + { url = "https://files.pythonhosted.org/packages/dc/9a/bcb8773b88e45fb5a5ea8339e2104d82c863a3b8558fbb2aadfe66df86b3/psycopg2_binary-2.9.10-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:35958ec9e46432d9076286dda67942ed6d968b9c3a6a2fd62b48939d1d78bf68", size = 2957617 }, + { url = "https://files.pythonhosted.org/packages/e2/6b/144336a9bf08a67d217b3af3246abb1d027095dab726f0687f01f43e8c03/psycopg2_binary-2.9.10-cp311-cp311-win32.whl", hash = "sha256:ecced182e935529727401b24d76634a357c71c9275b356efafd8a2a91ec07392", size = 1024618 }, + { url = "https://files.pythonhosted.org/packages/61/69/3b3d7bd583c6d3cbe5100802efa5beacaacc86e37b653fc708bf3d6853b8/psycopg2_binary-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:ee0e8c683a7ff25d23b55b11161c2663d4b099770f6085ff0a20d4505778d6b4", size = 1163816 }, + { url = "https://files.pythonhosted.org/packages/49/7d/465cc9795cf76f6d329efdafca74693714556ea3891813701ac1fee87545/psycopg2_binary-2.9.10-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:880845dfe1f85d9d5f7c412efea7a08946a46894537e4e5d091732eb1d34d9a0", size = 3044771 }, + { url = "https://files.pythonhosted.org/packages/8b/31/6d225b7b641a1a2148e3ed65e1aa74fc86ba3fee850545e27be9e1de893d/psycopg2_binary-2.9.10-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:9440fa522a79356aaa482aa4ba500b65f28e5d0e63b801abf6aa152a29bd842a", size = 3275336 }, + { url = "https://files.pythonhosted.org/packages/30/b7/a68c2b4bff1cbb1728e3ec864b2d92327c77ad52edcd27922535a8366f68/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e3923c1d9870c49a2d44f795df0c889a22380d36ef92440ff618ec315757e539", size = 2851637 }, + { url = "https://files.pythonhosted.org/packages/0b/b1/cfedc0e0e6f9ad61f8657fd173b2f831ce261c02a08c0b09c652b127d813/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7b2c956c028ea5de47ff3a8d6b3cc3330ab45cf0b7c3da35a2d6ff8420896526", size = 3082097 }, + { url = "https://files.pythonhosted.org/packages/18/ed/0a8e4153c9b769f59c02fb5e7914f20f0b2483a19dae7bf2db54b743d0d0/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f758ed67cab30b9a8d2833609513ce4d3bd027641673d4ebc9c067e4d208eec1", size = 3264776 }, + { url = "https://files.pythonhosted.org/packages/10/db/d09da68c6a0cdab41566b74e0a6068a425f077169bed0946559b7348ebe9/psycopg2_binary-2.9.10-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cd9b4f2cfab88ed4a9106192de509464b75a906462fb846b936eabe45c2063e", size = 3020968 }, + { url = "https://files.pythonhosted.org/packages/94/28/4d6f8c255f0dfffb410db2b3f9ac5218d959a66c715c34cac31081e19b95/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6dc08420625b5a20b53551c50deae6e231e6371194fa0651dbe0fb206452ae1f", size = 2872334 }, + { url = "https://files.pythonhosted.org/packages/05/f7/20d7bf796593c4fea95e12119d6cc384ff1f6141a24fbb7df5a668d29d29/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d7cd730dfa7c36dbe8724426bf5612798734bff2d3c3857f36f2733f5bfc7c00", size = 2822722 }, + { url = "https://files.pythonhosted.org/packages/4d/e4/0c407ae919ef626dbdb32835a03b6737013c3cc7240169843965cada2bdf/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:155e69561d54d02b3c3209545fb08938e27889ff5a10c19de8d23eb5a41be8a5", size = 2920132 }, + { url = "https://files.pythonhosted.org/packages/2d/70/aa69c9f69cf09a01da224909ff6ce8b68faeef476f00f7ec377e8f03be70/psycopg2_binary-2.9.10-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3cc28a6fd5a4a26224007712e79b81dbaee2ffb90ff406256158ec4d7b52b47", size = 2959312 }, + { url = "https://files.pythonhosted.org/packages/d3/bd/213e59854fafe87ba47814bf413ace0dcee33a89c8c8c814faca6bc7cf3c/psycopg2_binary-2.9.10-cp312-cp312-win32.whl", hash = "sha256:ec8a77f521a17506a24a5f626cb2aee7850f9b69a0afe704586f63a464f3cd64", size = 1025191 }, + { url = "https://files.pythonhosted.org/packages/92/29/06261ea000e2dc1e22907dbbc483a1093665509ea586b29b8986a0e56733/psycopg2_binary-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:18c5ee682b9c6dd3696dad6e54cc7ff3a1a9020df6a5c0f861ef8bfd338c3ca0", size = 1164031 }, + { url = "https://files.pythonhosted.org/packages/3e/30/d41d3ba765609c0763505d565c4d12d8f3c79793f0d0f044ff5a28bf395b/psycopg2_binary-2.9.10-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:26540d4a9a4e2b096f1ff9cce51253d0504dca5a85872c7f7be23be5a53eb18d", size = 3044699 }, + { url = "https://files.pythonhosted.org/packages/35/44/257ddadec7ef04536ba71af6bc6a75ec05c5343004a7ec93006bee66c0bc/psycopg2_binary-2.9.10-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e217ce4d37667df0bc1c397fdcd8de5e81018ef305aed9415c3b093faaeb10fb", size = 3275245 }, + { url = "https://files.pythonhosted.org/packages/1b/11/48ea1cd11de67f9efd7262085588790a95d9dfcd9b8a687d46caf7305c1a/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:245159e7ab20a71d989da00f280ca57da7641fa2cdcf71749c193cea540a74f7", size = 2851631 }, + { url = "https://files.pythonhosted.org/packages/62/e0/62ce5ee650e6c86719d621a761fe4bc846ab9eff8c1f12b1ed5741bf1c9b/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c4ded1a24b20021ebe677b7b08ad10bf09aac197d6943bfe6fec70ac4e4690d", size = 3082140 }, + { url = "https://files.pythonhosted.org/packages/27/ce/63f946c098611f7be234c0dd7cb1ad68b0b5744d34f68062bb3c5aa510c8/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3abb691ff9e57d4a93355f60d4f4c1dd2d68326c968e7db17ea96df3c023ef73", size = 3264762 }, + { url = "https://files.pythonhosted.org/packages/43/25/c603cd81402e69edf7daa59b1602bd41eb9859e2824b8c0855d748366ac9/psycopg2_binary-2.9.10-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8608c078134f0b3cbd9f89b34bd60a943b23fd33cc5f065e8d5f840061bd0673", size = 3020967 }, + { url = "https://files.pythonhosted.org/packages/5f/d6/8708d8c6fca531057fa170cdde8df870e8b6a9b136e82b361c65e42b841e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:230eeae2d71594103cd5b93fd29d1ace6420d0b86f4778739cb1a5a32f607d1f", size = 2872326 }, + { url = "https://files.pythonhosted.org/packages/ce/ac/5b1ea50fc08a9df82de7e1771537557f07c2632231bbab652c7e22597908/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909", size = 2822712 }, + { url = "https://files.pythonhosted.org/packages/c4/fc/504d4503b2abc4570fac3ca56eb8fed5e437bf9c9ef13f36b6621db8ef00/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1", size = 2920155 }, + { url = "https://files.pythonhosted.org/packages/b2/d1/323581e9273ad2c0dbd1902f3fb50c441da86e894b6e25a73c3fda32c57e/psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567", size = 2959356 }, + { url = "https://files.pythonhosted.org/packages/08/50/d13ea0a054189ae1bc21af1d85b6f8bb9bbc5572991055d70ad9006fe2d6/psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142", size = 2569224 }, ] [[package]] @@ -446,7 +457,7 @@ requires-dist = [ { name = "pecan" }, { name = "pecan-notario" }, { name = "pika" }, - { name = "psycopg2-binary", specifier = "==2.9.9" }, + { name = "psycopg2-binary", specifier = "==2.9.10" }, { name = "pytest", marker = "extra == 'test'" }, { name = "requests" }, { name = "sqlalchemy", specifier = "==1.4.53" }, From aa1e769ee40c6352cdb23cfdf4be6e4b5e2fd25f Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Mon, 31 Mar 2025 15:02:33 -0600 Subject: [PATCH 04/10] conftest: Rewrite fixtures to support sqlite So that we can run tests without having to set up infrastructure. This commit also adds a --db-url flag to py.test, so that the old postgres-specific behavior is still accessible by passing: --db-url 'postgresql+psycopg2://postgres@localhost:5432/shamantest' Signed-off-by: Zack Cerza --- shaman/tests/conftest.py | 192 ++++++++++----------------------------- 1 file changed, 49 insertions(+), 143 deletions(-) diff --git a/shaman/tests/conftest.py b/shaman/tests/conftest.py index f09ed77..208b0cf 100644 --- a/shaman/tests/conftest.py +++ b/shaman/tests/conftest.py @@ -1,28 +1,38 @@ +''' +conftest.py + +By default, unit tests run against a SQLite3 database, as that requires no +additional setup. To instead test against a PostgreSQL database, you might: + +podman run --rm -d -p 5432:5432 --name shamantest -e POSTGRES_HOST_AUTH_METHOD=trust -e POSTGRES_DB=shamantest postgres:16 +py.test --db-url postgresql+psycopg2://postgres@localhost:5432/shamantest' ... + +Don't forget to remove the container when you are finished: +podman rm -f shamantest +''' import os +import pytest + +from pecan import configuration, conf from pecan.testing import load_test_app -import subprocess +from shaman import models +from shaman.tests import util -from copy import deepcopy -from pecan import conf -from pecan import configuration -from sqlalchemy import create_engine -from sqlalchemy.pool import NullPool +def pytest_addoption(parser): + parser.addoption( + '--db-url', + default='sqlite:///dev.db', + help='The database to use for testing. For more information see conftest.py' + ) -from shaman import models as _db -from shaman.tests import util -import pytest -# needs running postgres, for example: podman run -d --rm -p 5432:5432 --name shamantest -e POSTGRES_HOST_AUTH_METHOD=trust -e POSTGRES_DB=shamantest postgres:16 -DBNAME = 'shamantest' -DBHOST = 'localhost' -DBPORT = '5432' -DBUSER = 'postgres' -BIND = f"postgresql+psycopg2://{DBUSER}@{DBHOST}:{DBPORT}" +@pytest.fixture(scope='session') +def db_url(pytestconfig): + return pytestconfig.getoption('db_url') class Factory(object): - def __init__(self, **kw): for k, v in kw.items(): setattr(self, k, v) @@ -56,140 +66,36 @@ def config_file(): return os.path.join(here, 'config.py') -def reload_config(): - from pecan import configuration - config = configuration.conf_from_file(config_file()).to_dict() - - # Add the appropriate connection string to the app config. - config['sqlalchemy_w'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - - config['sqlalchemy_ro'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - +@pytest.fixture(scope='function') +def config(db_url): + print(db_url) + configuration.set_config(dict()) + config_ = configuration.conf_from_file(config_file()) + config_.sqlalchemy_w.url = db_url + config_.sqlalchemy_ro.url = db_url configuration.set_config( - config, - overwrite=True - ) - _db.init_model() - - -@pytest.fixture(scope='session') -def app(request): - config = configuration.conf_from_file(config_file()).to_dict() - - # Add the appropriate connection string to the app config. - config['sqlalchemy_w'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - - config['sqlalchemy_ro'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - # Set up a fake app - app = TestApp(load_test_app(config)) - return app - - -@pytest.fixture(scope='session') -def connection(app, request): - """Session-wide test database.""" - # Connect and create the temporary database - print("=" * 80) - print("CREATING TEMPORARY DATABASE FOR TESTS") - print("=" * 80) - subprocess.call(['dropdb', - '-h', DBHOST, - '-p', DBPORT, - '-U', DBUSER, DBNAME]) - subprocess.call(['createdb', - '-h', DBHOST, - '-p', DBPORT, - '-U', DBUSER, DBNAME]) - - # Bind and create the database tables - _db.clear() - engine_url = '%s/%s' % (BIND, DBNAME) - - db_engine = create_engine( - engine_url, - encoding='utf-8', - poolclass=NullPool) - - # AKA models.start() - _db.Session.bind = db_engine - _db.metadata.bind = _db.Session.bind - - _db.Base.metadata.create_all(db_engine) - _db.commit() - _db.clear() - - def teardown(): - _db.Base.metadata.drop_all(db_engine) - - request.addfinalizer(teardown) - - # Slap our test app on it - _db.app = app - return _db - + config_.to_dict(), + overwrite=True, + ) + return conf @pytest.fixture(scope='function') -def session(connection, request): - """Creates a new database session for a test.""" - _config = configuration.conf_from_file(config_file()).to_dict() - config = deepcopy(_config) - - # Add the appropriate connection string to the app config. - config['sqlalchemy_w'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - - config['sqlalchemy_ro'] = { - 'url': '%s/%s' % (BIND, DBNAME), - 'encoding': 'utf-8', - 'poolclass': NullPool - } - - connection.start() +def app(request, config): + app = TestApp(load_test_app(config.to_dict())) + db_engine = conf.sqlalchemy_w.engine + models.start() + models.Base.metadata.create_all(db_engine) + models.Session.commit() + models.Session.flush() + models.clear() def teardown(): - from sqlalchemy.engine import reflection - - # Tear down and dispose the DB binding - connection.clear() - - # start a transaction - engine = conf.sqlalchemy_w.engine - conn = engine.connect() - trans = conn.begin() - - inspector = reflection.Inspector.from_engine(engine) - - # gather all data first before dropping anything. - # some DBs lock after things have been dropped in - # a transaction. - conn.execute("TRUNCATE TABLE %s RESTART IDENTITY CASCADE" % ( - ', '.join(inspector.get_table_names()) - )) - - trans.commit() - conn.close() + db_engine = conf.sqlalchemy_w.engine + models.rollback() + models.Base.metadata.drop_all(db_engine) request.addfinalizer(teardown) - return connection + return app class TestApp(object): From b2f26fe6eb32153c765927783a7b2133efa12cbc Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Mon, 31 Mar 2025 15:01:44 -0600 Subject: [PATCH 05/10] tests: Use app fixture instead of session This improves lifecycle management for the test db. Signed-off-by: Zack Cerza --- shaman/tests/controllers/test_builds.py | 68 ++--- shaman/tests/controllers/test_bus.py | 12 +- shaman/tests/controllers/test_health.py | 8 +- shaman/tests/controllers/test_nodes.py | 64 ++--- shaman/tests/controllers/test_repos.py | 330 ++++++++++++------------ shaman/tests/controllers/test_root.py | 24 +- shaman/tests/controllers/test_search.py | 158 ++++++------ shaman/tests/models/test_builds.py | 44 ++-- shaman/tests/models/test_repos.py | 34 +-- shaman/tests/test_util.py | 90 ++++--- 10 files changed, 420 insertions(+), 412 deletions(-) diff --git a/shaman/tests/controllers/test_builds.py b/shaman/tests/controllers/test_builds.py index ea25c9f..2293084 100644 --- a/shaman/tests/controllers/test_builds.py +++ b/shaman/tests/controllers/test_builds.py @@ -25,46 +25,46 @@ class TestProjectController(object): def setup_method(self): self.data = get_build_data() - def test_list_ref_by_id(self, session): + def test_list_ref_by_id(self, app): project = Project(name='ceph') Build(build_id=1, project=project, ref='master') Build(build_id=2, project=project, ref='master') Build(build_id=100, project=project, ref='master') commit() - result = session.app.get('/builds/ceph/master/') + result = app.get('/builds/ceph/master/') assert result.namespace['builds'][0].build_id == '100' assert result.namespace['builds'][1].build_id == '2' assert result.namespace['builds'][2].build_id == '1' - def test_list_builds_by_id(self, session): + def test_list_builds_by_id(self, app): project = Project(name='ceph') Build(build_id=1, project=project, ref='master') Build(build_id=2, project=project, ref='master') Build(build_id=100, project=project, ref='master') commit() - result = session.app.get('/builds/ceph/') + result = app.get('/builds/ceph/') assert result.namespace['builds'][0].build_id == '100' assert result.namespace['builds'][1].build_id == '2' assert result.namespace['builds'][2].build_id == '1' - def test_list_sha1s_by_id(self, session): + def test_list_sha1s_by_id(self, app): project = Project(name='ceph') Build(build_id=1, project=project, ref='master', sha1='1234') Build(build_id=2, project=project, ref='master', sha1='1234') Build(build_id=100, project=project, ref='master', sha1='1234') commit() - result = session.app.get('/builds/ceph/master/1234/') + result = app.get('/builds/ceph/master/1234/') assert result.namespace['builds'][0].build_id == '100' assert result.namespace['builds'][1].build_id == '2' assert result.namespace['builds'][2].build_id == '1' - def test_list_flavors_by_id(self, session): + def test_list_flavors_by_id(self, app): project = Project(name='ceph') Build(build_id=1, project=project, ref='master', sha1='1234', flavor='default') Build(build_id=2, project=project, ref='master', sha1='1234', flavor='default') Build(build_id=100, project=project, ref='master', sha1='1234', flavor='default') commit() - result = session.app.get('/builds/ceph/master/1234/default/') + result = app.get('/builds/ceph/master/1234/default/') assert result.namespace['builds'][0].build_id == '100' assert result.namespace['builds'][1].build_id == '2' assert result.namespace['builds'][2].build_id == '1' @@ -75,8 +75,8 @@ class TestApiProjectController(object): def setup_method(self): self.data = get_build_data() - def test_create_a_build(self, session): - result = session.app.post_json('/api/builds/ceph/', params=self.data) + def test_create_a_build(self, app): + result = app.post_json('/api/builds/ceph/', params=self.data) assert result.status_int == 200 build = Build.get(1) assert build.ref == "master" @@ -88,68 +88,68 @@ def test_create_a_build(self, session): assert build.extra["version"] == "10.2.2" assert not build.distro - def test_update_build(self, session): - session.app.post_json('/api/builds/ceph/', params=self.data) + def test_update_build(self, app): + app.post_json('/api/builds/ceph/', params=self.data) data = self.data.copy() data['status'] = "completed" - result = session.app.post_json('/api/builds/ceph/', params=data) + result = app.post_json('/api/builds/ceph/', params=data) assert result.status_int == 200 build = Build.get(1) assert build.status == "completed" - def test_update_build_same_url_different_sha1(self, session): + def test_update_build_same_url_different_sha1(self, app): # this tests the situation where a new jenkins instance # is spun up at the same URL and the jenkins urls are # now duplicating - session.app.post_json('/api/builds/ceph/', params=self.data) + app.post_json('/api/builds/ceph/', params=self.data) data = self.data.copy() data['sha1'] = "new-sha1" - result = session.app.post_json('/api/builds/ceph/', params=data) + result = app.post_json('/api/builds/ceph/', params=data) assert result.status_int == 200 assert len(Build.query.all()) == 2 - def test_update_queued_build_creates_single_object(self, session): + def test_update_queued_build_creates_single_object(self, app): data = get_build_data(status='queued', url='jenkins.ceph.com/trigger') - session.app.post_json('/api/builds/ceph/', params=data) + app.post_json('/api/builds/ceph/', params=data) data = get_build_data(status='completed') - session.app.post_json('/api/builds/ceph/', params=data) + app.post_json('/api/builds/ceph/', params=data) assert len(Build.query.all()) == 1 - def test_update_queued_build_is_completed(self, session): + def test_update_queued_build_is_completed(self, app): data = get_build_data(status='queued', url='jenkins.ceph.com/trigger') - session.app.post_json('/api/builds/ceph/', params=data) + app.post_json('/api/builds/ceph/', params=data) data = get_build_data(status='completed') - session.app.post_json('/api/builds/ceph/', params=data) + app.post_json('/api/builds/ceph/', params=data) assert Build.get(1).status == 'completed' - def test_lists_refs(self, session): - session.app.post_json('/api/builds/ceph/', params=self.data) - result = session.app.get('/api/builds/ceph/') + def test_lists_refs(self, app): + app.post_json('/api/builds/ceph/', params=self.data) + result = app.get('/api/builds/ceph/') assert "master" in result.json class TestProjectsAPIController(object): - def test_lists_projects_with_ref(self, session): - session.app.post_json('/api/builds/ceph/', params=get_build_data()) - result = session.app.get('/api/builds/') + def test_lists_projects_with_ref(self, app): + app.post_json('/api/builds/ceph/', params=get_build_data()) + result = app.get('/api/builds/') assert 'ceph' in result.json assert result.json['ceph'][0] == "master" class TestRefsAPIController(object): - def test_lists_sha1s(self, session): - session.app.post_json('/api/builds/ceph/', params=get_build_data()) - result = session.app.get('/api/builds/ceph/master/') + def test_lists_sha1s(self, app): + app.post_json('/api/builds/ceph/', params=get_build_data()) + result = app.get('/api/builds/ceph/master/') assert 'sha1' in result.json class TestSHA1APIController(object): - def test_lists_builds(self, session): - session.app.post_json('/api/builds/ceph/', params=get_build_data()) - result = session.app.get('/api/builds/ceph/master/sha1/') + def test_lists_builds(self, app): + app.post_json('/api/builds/ceph/', params=get_build_data()) + result = app.get('/api/builds/ceph/master/sha1/') assert len(result.json) == 1 assert result.json[0]["ref"] == "master" assert result.json[0]["sha1"] == "sha1" diff --git a/shaman/tests/controllers/test_bus.py b/shaman/tests/controllers/test_bus.py index b4a212b..a187ada 100644 --- a/shaman/tests/controllers/test_bus.py +++ b/shaman/tests/controllers/test_bus.py @@ -4,12 +4,12 @@ class TestBusApiController(object): - def test_post_index_basic_auth(self, session): - result = session.app.post_json('/api/bus/ceph/test', params={}) + def test_post_index_basic_auth(self, app): + result = app.post_json('/api/bus/ceph/test', params={}) assert result.status_int == 200 - def test_post_index_github_auth_fails(self, session): - result = session.app.post_json( + def test_post_index_github_auth_fails(self, app): + result = app.post_json( '/api/bus/ceph/test', headers={'X-Hub-Signature': 'fail'}, params={}, @@ -17,9 +17,9 @@ def test_post_index_github_auth_fails(self, session): ) assert result.status_int == 401 - def test_post_index_github_auth_succeeds(self, session): + def test_post_index_github_auth_succeeds(self, app): signature = "sha1={}".format(hmac.new(b'secret', b'{}', sha1).hexdigest()) - result = session.app.post_json( + result = app.post_json( '/api/bus/ceph/test', headers={'X-Hub-Signature': signature}, params={}, diff --git a/shaman/tests/controllers/test_health.py b/shaman/tests/controllers/test_health.py index 8e56c50..456cfa8 100644 --- a/shaman/tests/controllers/test_health.py +++ b/shaman/tests/controllers/test_health.py @@ -3,12 +3,12 @@ class TestHealthController(object): - def test_passes_health_check(self, session, monkeypatch): + def test_passes_health_check(self, app, monkeypatch): monkeypatch.setattr(health.checks, "is_healthy", lambda: True) - result = session.app.get("/_health/") + result = app.get("/_health/") assert result.status_int == 204 - def test_fails_health_check(self, session, monkeypatch): + def test_fails_health_check(self, app, monkeypatch): monkeypatch.setattr(health.checks, "is_healthy", lambda: False) - result = session.app.get("/_health/", expect_errors=True) + result = app.get("/_health/", expect_errors=True) assert result.status_int == 500 diff --git a/shaman/tests/controllers/test_nodes.py b/shaman/tests/controllers/test_nodes.py index d1ed644..ca76564 100644 --- a/shaman/tests/controllers/test_nodes.py +++ b/shaman/tests/controllers/test_nodes.py @@ -1,25 +1,25 @@ -from shaman.models import Node +from shaman.models import Node, commit from shaman.controllers.api import nodes class TestNodeController(object): - def test_get_no_nodes(self, session): - result = session.app.get("/api/nodes/") + def test_get_no_nodes(self, app): + result = app.get("/api/nodes/") assert result.status_int == 200 assert result.json == {} - def test_get_one_node(self, session): + def test_get_one_node(self, app): Node("chacra.ceph.com") - session.commit() - result = session.app.get("/api/nodes/") + commit() + result = app.get("/api/nodes/") assert list(result.json.keys()) == ["chacra.ceph.com"] - def test_get_multiple_nodes(self, session): + def test_get_multiple_nodes(self, app): Node("chacra01.ceph.com") Node("chacra02.ceph.com") - session.commit() - result = session.app.get("/api/nodes/") + commit() + result = app.get("/api/nodes/") assert set(result.json.keys()) == set(["chacra01.ceph.com", "chacra02.ceph.com"]) @@ -32,73 +32,73 @@ def _check_node_health(node): class TestNodesContoller(object): - def test_node_not_created(self, session): - result = session.app.get("/api/nodes/chacra.ceph.com/", expect_errors=True) + def test_node_not_created(self, app): + result = app.get("/api/nodes/chacra.ceph.com/", expect_errors=True) assert result.status_int == 404 - def test_create_node(self, session, monkeypatch): + def test_create_node(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) assert n.host == "chacra.ceph.com" - def test_node_fails_initial_check(self, session, monkeypatch): + def test_node_fails_initial_check(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(False)) - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) assert n.host == "chacra.ceph.com" assert not n.healthy - def test_updates_last_check_time(self, session, monkeypatch): + def test_updates_last_check_time(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) last_check = n.last_check.time() - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) assert n.last_check.time() > last_check - def test_updates_down_count(self, session, monkeypatch): + def test_updates_down_count(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) n.down_count = 2 - session.commit() - session.app.post("/api/nodes/chacra.ceph.com/") + commit() + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) assert n.down_count == 0 - def test_updates_healthy(self, session, monkeypatch): + def test_updates_healthy(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) - session.app.post("/api/nodes/chacra.ceph.com/") + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) n.healthy = False - session.commit() - session.app.post("/api/nodes/chacra.ceph.com/") + commit() + app.post("/api/nodes/chacra.ceph.com/") n = Node.get(1) assert n.healthy - def test_get_next_node_succeeds(self, session, monkeypatch): + def test_get_next_node_succeeds(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) Node("chacra.ceph.com") - session.commit() + commit() def _get_next_node(): node = Node.get(1) return node monkeypatch.setattr(nodes, "get_next_node", _get_next_node) - result = session.app.get("/api/nodes/next/") + result = app.get("/api/nodes/next/") assert result.body.decode() == "https://chacra.ceph.com/" - def test_get_next_node_fails(self, session, monkeypatch): + def test_get_next_node_fails(self, app, monkeypatch): monkeypatch.setattr(nodes, "check_node_health", mock_check_node_health(True)) Node("chacra.ceph.com") - session.commit() + commit() def _get_next_node(): return None monkeypatch.setattr(nodes, "get_next_node", _get_next_node) - result = session.app.get("/api/nodes/next/", expect_errors=True) + result = app.get("/api/nodes/next/", expect_errors=True) assert result.status_int == 404 diff --git a/shaman/tests/controllers/test_repos.py b/shaman/tests/controllers/test_repos.py index ce539c6..e66fc38 100644 --- a/shaman/tests/controllers/test_repos.py +++ b/shaman/tests/controllers/test_repos.py @@ -1,48 +1,48 @@ -from shaman.models import Project, Repo +from shaman.models import Project, Repo, commit class TestApiController(object): - def test_get_index_no_projects(self, session): - result = session.app.get('/api/') + def test_get_index_no_projects(self, app): + result = app.get('/api/') assert result.status_int == 200 assert result.json == {'repos': []} - def test_get_index_shows_projects(self, session): + def test_get_index_shows_projects(self, app): Project("ceph") - session.commit() - result = session.app.get('/api/') + commit() + result = app.get('/api/') assert result.status_int == 200 assert result.json == {'repos': ['ceph']} class TestProjectsController(object): - def test_get_index_no_projects(self, session): - result = session.app.get('/api/repos/') + def test_get_index_no_projects(self, app): + result = app.get('/api/repos/') assert result.status_int == 200 assert result.json == {} - def test_list_a_project(self, session): + def test_list_a_project(self, app): Project("ceph") - session.commit() - result = session.app.get('/api/repos/') + commit() + result = app.get('/api/repos/') assert result.status_int == 200 assert "ceph" in result.json.keys() - def test_one_project_list_length(self, session): + def test_one_project_list_length(self, app): Project("ceph") - session.commit() - result = session.app.get('/api/repos/') + commit() + result = app.get('/api/repos/') assert result.status_int == 200 assert len(result.json.keys()) == 1 - def test_list_a_few_projects(self, session): + def test_list_a_few_projects(self, app): for p in range(20): Project('foo_%s' % p) - session.commit() + commit() - result = session.app.get('/api/repos/') + result = app.get('/api/repos/') assert result.status_int == 200 assert len(result.json) == 20 @@ -61,19 +61,19 @@ def setup_method(self): extra=dict(version="10.2.2"), ) - def test_get_project_repos_is_empty(self, session): + def test_get_project_repos_is_empty(self, app): Project("ceph") - session.commit() - result = session.app.get('/api/repos/ceph/') + commit() + result = app.get('/api/repos/ceph/') assert result.json == [] - def test_get_project_with_a_repo(self, session): - session.app.post_json('/api/repos/ceph/', params=self.repo_data) - result = session.app.get('/api/repos/ceph/') + def test_get_project_with_a_repo(self, app): + app.post_json('/api/repos/ceph/', params=self.repo_data) + result = app.get('/api/repos/ceph/') assert result.json == ["jewel"] - def test_create_a_repo(self, session): - result = session.app.post_json('/api/repos/ceph/', params=self.repo_data) + def test_create_a_repo(self, app): + result = app.post_json('/api/repos/ceph/', params=self.repo_data) assert result.status_int == 200 repo = Repo.get(1) assert repo.ref == "jewel" @@ -81,48 +81,50 @@ def test_create_a_repo(self, session): assert repo.flavor == "default" assert repo.extra["version"] == "10.2.2" - def test_update_a_repo_status(self, session): - result = session.app.post_json('/api/repos/ceph/', params=self.repo_data) + def test_update_a_repo_status(self, app): + result = app.post_json('/api/repos/ceph/', params=self.repo_data) assert result.status_int == 200 assert Repo.get(1).status == "requested" new_data = self.repo_data.copy() new_data["status"] = "ready" - result = session.app.post_json('/api/repos/ceph/', params=new_data) + result = app.post_json('/api/repos/ceph/', params=new_data) assert Repo.get(1).status == "ready" - def test_delete_a_repo(self, session): - result = session.app.post_json('/api/repos/ceph/', params=self.repo_data) + def test_delete_a_repo(self, app): + result = app.post_json('/api/repos/ceph/', params=self.repo_data) assert result.status_int == 200 assert Repo.get(1).status == "requested" new_data = self.repo_data.copy() new_data["status"] = "deleted" - result = session.app.post_json('/api/repos/ceph/', params=new_data) + result = app.post_json('/api/repos/ceph/', params=new_data) + commit() + assert result.status_int == 200 assert not Repo.get(1) - def test_update_a_repo_url(self, session): - result = session.app.post_json('/api/repos/ceph/', params=self.repo_data) + def test_update_a_repo_url(self, app): + result = app.post_json('/api/repos/ceph/', params=self.repo_data) assert result.status_int == 200 assert not Repo.get(1).url new_data = self.repo_data.copy() new_data["url"] = "chacra.ceph.com/r/ceph/jewel/" - result = session.app.post_json('/api/repos/ceph/', params=new_data) + result = app.post_json('/api/repos/ceph/', params=new_data) assert Repo.get(1).url == "chacra.ceph.com/r/ceph/jewel/" - def test_add_repo_with_archs(self, session): + def test_add_repo_with_archs(self, app): data = self.repo_data.copy() data["archs"] = ["x86_64", "arm64"] - session.app.post_json('/api/repos/ceph/', params=data) + app.post_json('/api/repos/ceph/', params=data) repo = Repo.get(1) assert len(repo.archs) == 2 - def test_update_repo_with_archs(self, session): + def test_update_repo_with_archs(self, app): data = self.repo_data.copy() data["archs"] = ["x86_64"] - session.app.post_json('/api/repos/ceph/', params=data) + app.post_json('/api/repos/ceph/', params=data) repo = Repo.get(1) assert len(repo.archs) == 1 data["archs"] = ["x86_64", "arm64"] - session.app.post_json('/api/repos/ceph/', params=data) + app.post_json('/api/repos/ceph/', params=data) repo = Repo.get(1) assert len(repo.archs) == 2 @@ -161,75 +163,75 @@ def base_repo_data(**kw): class TestRefController(object): - def test_get_existing_ref(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/') + def test_get_existing_ref(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/') assert result.json == ["45107e21c568dd033c2f0a3107dec8f0b0e58374"] - def test_same_refs_show_once(self, session): + def test_same_refs_show_once(self, app): repo_1 = base_repo_data() repo_2 = base_repo_data() repo_2['chacra_url'] = 'https://localhost/' - session.app.post_json('/api/repos/ceph/', params=repo_1) - session.app.post_json('/api/repos/ceph/', params=repo_2) - result = session.app.get('/api/repos/ceph/jewel/') + app.post_json('/api/repos/ceph/', params=repo_1) + app.post_json('/api/repos/ceph/', params=repo_2) + result = app.get('/api/repos/ceph/jewel/') assert result.json == ["45107e21c568dd033c2f0a3107dec8f0b0e58374"] class TestSHA1Controller(object): - def test_get_existing_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/') + def test_get_existing_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/') assert result.json == ["ubuntu"] - def test_get_latest_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/latest/') + def test_get_latest_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/latest/') assert result.json == ["ubuntu"] - def test_get_one_latest_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - session.app.post_json( + def test_get_one_latest_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + app.post_json( '/api/repos/ceph/', params=base_repo_data(distro='centos', sha1='aaaaa') ) - result = session.app.get('/api/repos/ceph/jewel/latest/') + result = app.get('/api/repos/ceph/jewel/latest/') assert result.json == ["centos"] - def test_get_latest_sha1_requested_504s(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='requested')) - result = session.app.get('/api/repos/ceph/jewel/latest/', expect_errors=True) + def test_get_latest_sha1_requested_504s(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='requested')) + result = app.get('/api/repos/ceph/jewel/latest/', expect_errors=True) assert result.status_int == 504 class TestDistroController(object): - def test_get_existing_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get( + def test_get_existing_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get( '/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/' ) assert result.json == ["xenial"] - def test_same_distro_versions_show_once(self, session): + def test_same_distro_versions_show_once(self, app): repo_1 = base_repo_data() repo_2 = base_repo_data() repo_2['chacra_url'] = 'https://localhost/' - session.app.post_json('/api/repos/ceph/', params=repo_1) - session.app.post_json('/api/repos/ceph/', params=repo_2) - result = session.app.get( + app.post_json('/api/repos/ceph/', params=repo_1) + app.post_json('/api/repos/ceph/', params=repo_2) + result = app.get( '/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/' ) assert result.json == ["xenial"] - def test_repos_are_distinct(self, session): + def test_repos_are_distinct(self, app): # note the sha1 is different for the only 'ubuntu' build repo_1 = base_repo_data(sha1='aaa', distro='ubuntu') repo_2 = base_repo_data(distro='debian') - session.app.post_json('/api/repos/ceph/', params=repo_1) - session.app.post_json('/api/repos/ceph/', params=repo_2) - result = session.app.get( + app.post_json('/api/repos/ceph/', params=repo_1) + app.post_json('/api/repos/ceph/', params=repo_2) + result = app.get( '/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/' ) assert result.json == [] @@ -237,104 +239,104 @@ def test_repos_are_distinct(self, session): class TestDistroVersionController(object): - def test_get_existing_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/') + def test_get_existing_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/') assert result.json[0]['distro_version'] == '16.04' assert result.json[0]['distro_codename'] == 'xenial' assert result.json[0]['flavor'] == 'default' - def test_get_latest_repo_unavailable(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get( + def test_get_latest_repo_unavailable(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get( '/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', params={'arch': 'i386'}, expect_errors=True) assert result.status_int == 504 - def test_get_latest_repo_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) + def test_get_latest_repo_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_arch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/x86_64/', expect_errors=True) + def test_get_latest_repo_arch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/x86_64/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_directory_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', distro="centos", distro_version="7")) - result = session.app.get('/api/repos/ceph/jewel/latest/centos/7/x86_64/noarch/repodata/repomd.xml', expect_errors=True) + def test_get_latest_repo_directory_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', distro="centos", distro_version="7")) + result = app.get('/api/repos/ceph/jewel/latest/centos/7/x86_64/noarch/repodata/repomd.xml', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_distro(self, session): + def test_get_latest_repo_sha1_not_ready_for_distro(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="0")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", distro="test")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="1")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=x86_64', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="0")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", distro="test")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="1")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=x86_64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_flavor(self, session): + def test_get_latest_repo_sha1_not_ready_for_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2", flavor="notcmalloc")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2", flavor="notcmalloc")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_default_flavor(self, session): + def test_get_latest_repo_sha1_not_ready_for_default_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', flavor="notcmalloc")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building')) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', flavor="notcmalloc")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) assert result.status_int == 504 - def test_get_latest_repo_sha1_not_ready_for_custom_flavor(self, session): + def test_get_latest_repo_sha1_not_ready_for_custom_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', flavor="notcmalloc")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', flavor="notcmalloc")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_ready_noarch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', archs=["noarch"])) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) + def test_get_latest_repo_ready_noarch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', archs=["noarch"])) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_valid_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=arm64', expect_errors=True) + def test_get_latest_repo_valid_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=arm64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_valid_extra_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=x86_64', expect_errors=True) + def test_get_latest_repo_valid_extra_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=x86_64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_invalid_extra_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=aarch64', expect_errors=True) + def test_get_latest_repo_invalid_extra_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/repo/?arch=aarch64', expect_errors=True) assert result.status_int == 504 class TestFlavorsController(object): - def test_get_existing_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/flavors/') + def test_get_existing_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/flavors/') assert result.json == ["default"] class TestFlavorController(object): - def test_get_existing_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/flavors/default/') + def test_get_existing_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/repos/ceph/jewel/45107e21c568dd033c2f0a3107dec8f0b0e58374/ubuntu/xenial/flavors/default/') assert result.json[0]['distro_codename'] == 'xenial' assert result.json[0]['distro_version'] == '16.04' assert result.json[0]['project'] == 'ceph' @@ -344,81 +346,81 @@ def test_get_existing_sha1(self, session): assert result.json[0]['sha1'] == '45107e21c568dd033c2f0a3107dec8f0b0e58374' assert sorted(result.json[0]['archs']) == sorted(["arm64", "x86_64"]) - def test_get_latest_repo_unavailable(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='requested')) - result = session.app.get( + def test_get_latest_repo_unavailable(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='requested')) + result = app.get( '/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True ) assert result.status_int == 504 - def test_get_latest_repo_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) + def test_get_latest_repo_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_arch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/x86_64/', expect_errors=True) + def test_get_latest_repo_arch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/x86_64/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_directory_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', distro="centos", distro_version="7")) - result = session.app.get('/api/repos/ceph/jewel/latest/centos/7/flavors/default/x86_64/noarch/repodata/repomd.xml', expect_errors=True) + def test_get_latest_repo_directory_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', distro="centos", distro_version="7")) + result = app.get('/api/repos/ceph/jewel/latest/centos/7/flavors/default/x86_64/noarch/repodata/repomd.xml', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_distro(self, session): + def test_get_latest_repo_sha1_not_ready_for_distro(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="0")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", distro="test")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="1")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=x86_64', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="0")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", distro="test")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="1")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=x86_64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_flavor(self, session): + def test_get_latest_repo_sha1_not_ready_for_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2", flavor="notcmalloc")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2", flavor="notcmalloc")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_ready_for_non_default_flavor(self, session): + def test_get_latest_repo_sha1_ready_for_non_default_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", flavor="notcmalloc")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2", flavor="notcmalloc")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2")) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/notcmalloc/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="1", flavor="notcmalloc")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', sha1="2", flavor="notcmalloc")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', sha1="2")) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/notcmalloc/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_sha1_not_ready_for_non_default_flavor(self, session): + def test_get_latest_repo_sha1_not_ready_for_non_default_flavor(self, app): # this tests for a regression where the latest sha1 that is picked for a distro does not # have a ready repo and a 504 is eventually given - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', flavor="notcmalloc")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/notcmalloc/repo/', expect_errors=True) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='building', flavor="notcmalloc")) + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/notcmalloc/repo/', expect_errors=True) assert result.status_int == 504 - def test_get_latest_repo_ready_noarch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', archs=["noarch"])) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) + def test_get_latest_repo_ready_noarch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready', archs=["noarch"])) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_valid_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=arm64', expect_errors=True) + def test_get_latest_repo_valid_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=arm64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_valid_extra_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=x86_64', expect_errors=True) + def test_get_latest_repo_valid_extra_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=x86_64', expect_errors=True) assert result.status_int == 302 - def test_get_latest_repo_invalid_extra_arch_ready(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) - result = session.app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=aarch64', expect_errors=True) + def test_get_latest_repo_invalid_extra_arch_ready(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(status='ready')) + result = app.get('/api/repos/ceph/jewel/latest/ubuntu/xenial/flavors/default/repo/?arch=aarch64', expect_errors=True) assert result.status_int == 504 diff --git a/shaman/tests/controllers/test_root.py b/shaman/tests/controllers/test_root.py index d4db912..27f2fbc 100644 --- a/shaman/tests/controllers/test_root.py +++ b/shaman/tests/controllers/test_root.py @@ -4,40 +4,40 @@ class TestRootController(object): - def test_gets_five_days_of_area_data(self, session): - result = session.app.get('/') + def test_gets_five_days_of_area_data(self, app): + result = app.get('/') # this is super naive but the list is really all a string # so JS can consume it assert len(result.namespace['area_data'].split(',')) == 10 - def test_gets_no_projects_by_defaut(self, session): - result = session.app.get('/') + def test_gets_no_projects_by_defaut(self, app): + result = app.get('/') assert result.namespace['projects'] == [] - def test_no_latest_repos(self, session): - result = session.app.get('/') + def test_no_latest_repos(self, app): + result = app.get('/') assert result.namespace['latest_repos'] == [] - def test_no_latest_builds(self, session): - result = session.app.get('/') + def test_no_latest_builds(self, app): + result = app.get('/') assert result.namespace['latest_builds'] == [] - def test_repos_from_today(self, session): + def test_repos_from_today(self, app): models.Repo( project=models.Project(name='ceph'), distro="ubuntu", distro_version="xenial", status="ready") models.commit() - result = session.app.get('/') + result = app.get('/') now = datetime.datetime.now(datetime.timezone.utc) today_str = now.strftime('%Y-%m-%d') assert "'ceph': 1" in result.namespace['area_data'] assert today_str in result.namespace['area_data'] - def test_no_builds_from_today(self, session): + def test_no_builds_from_today(self, app): # create a build, no repos models.Build(project=models.Project(name='ceph'), status="ready") models.commit() - result = session.app.get('/') + result = app.get('/') assert "'ceph': 0" not in result.namespace['area_data'] diff --git a/shaman/tests/controllers/test_search.py b/shaman/tests/controllers/test_search.py index 0000aa0..d86f221 100644 --- a/shaman/tests/controllers/test_search.py +++ b/shaman/tests/controllers/test_search.py @@ -23,88 +23,88 @@ def base_repo_data(**kw): class TestSearchController(object): - def test_get_no_repos(self, session): - result = session.app.get('/api/search/', params={'project': 'ceph'}) + def test_get_no_repos(self, app): + result = app.get('/api/search/', params={'project': 'ceph'}) assert result.json == [] - def test_get_existing_repo(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/search/', params={'project': 'ceph'}) + def test_get_existing_repo(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/search/', params={'project': 'ceph'}) assert result.json[0]['sha1'] == "45107e21c568dd033c2f0a3107dec8f0b0e58374" assert result.json[0]['ref'] == "jewel" - def test_get_no_matching_repo_for_ref(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/search/', params={'project': 'ceph', 'ref': 'frufru'}) + def test_get_no_matching_repo_for_ref(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/search/', params={'project': 'ceph', 'ref': 'frufru'}) assert result.json == [] - def test_project_can_be_omitted(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/search/', params={'ref': 'jewel'}) + def test_project_can_be_omitted(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/search/', params={'ref': 'jewel'}) assert result.json[0]['sha1'] == "45107e21c568dd033c2f0a3107dec8f0b0e58374" assert result.json[0]['ref'] == "jewel" - def test_filter_by_single_distro(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) + def test_filter_by_single_distro(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) centos_data = base_repo_data(distro="centos", distro_version="7") centos_data["chacra_url"] = "centos" - session.app.post_json('/api/repos/ceph/', params=centos_data) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial'}) + app.post_json('/api/repos/ceph/', params=centos_data) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial'}) assert len(result.json) == 1 assert result.json[0]["distro"] == "ubuntu" assert result.json[0]["distro_codename"] == "xenial" - def test_filter_by_single_distro_and_arch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) + def test_filter_by_single_distro_and_arch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) centos_data = base_repo_data(distro="centos", distro_version="7") centos_data["chacra_url"] = "centos" - session.app.post_json('/api/repos/ceph/', params=centos_data) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) + app.post_json('/api/repos/ceph/', params=centos_data) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) assert len(result.json) == 1 assert result.json[0]["distro"] == "ubuntu" assert result.json[0]["distro_codename"] == "xenial" assert result.json[0]["archs"] == ["x86_64"] - def test_filter_by_same_distro_with_different_archs(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["arm64"], chacra_url="1")) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) + def test_filter_by_same_distro_with_different_archs(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["arm64"], chacra_url="1")) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) assert len(result.json) == 1 assert result.json[0]["distro"] == "ubuntu" assert result.json[0]["distro_codename"] == "xenial" assert result.json[0]["archs"] == ["x86_64"] - def test_filter_by_single_distro_with_multiple_archs(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["x86_64", "arm64"])) + def test_filter_by_single_distro_with_multiple_archs(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["x86_64", "arm64"])) centos_data = base_repo_data(distro="centos", distro_version="7") centos_data["chacra_url"] = "centos" - session.app.post_json('/api/repos/ceph/', params=centos_data) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) + app.post_json('/api/repos/ceph/', params=centos_data) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial/x86_64'}) assert len(result.json) == 1 assert result.json[0]["distro"] == "ubuntu" assert result.json[0]["distro_codename"] == "xenial" assert "x86_64" in result.json[0]["archs"] - def test_filter_by_multiple_distros(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) + def test_filter_by_multiple_distros(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) centos_data = base_repo_data(distro="centos", distro_version="7") - session.app.post_json('/api/repos/ceph/', params=centos_data) + app.post_json('/api/repos/ceph/', params=centos_data) jessie_data = base_repo_data(distro="debian", distro_version="jessie") - session.app.post_json('/api/repos/ceph/', params=jessie_data) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial,centos/7'}) + app.post_json('/api/repos/ceph/', params=jessie_data) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial,centos/7'}) assert len(result.json) == 2 assert result.json[0]["distro"] == "centos" assert result.json[0]["distro_version"] == "7" assert result.json[1]["distro"] == "ubuntu" assert result.json[1]["distro_codename"] == "xenial" - def test_filter_by_multiple_distros_with_arch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) + def test_filter_by_multiple_distros_with_arch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) centos_data = base_repo_data(distro="centos", distro_version="7", archs=["arm64"]) - session.app.post_json('/api/repos/ceph/', params=centos_data) + app.post_json('/api/repos/ceph/', params=centos_data) jessie_data = base_repo_data(distro="debian", distro_version="jessie") - session.app.post_json('/api/repos/ceph/', params=jessie_data) - result = session.app.get('/api/search/', params={'distros': 'ubuntu/xenial,centos/7/arm64'}) + app.post_json('/api/repos/ceph/', params=jessie_data) + result = app.get('/api/search/', params={'distros': 'ubuntu/xenial,centos/7/arm64'}) assert len(result.json) == 2 assert result.json[0]["distro"] == "centos" assert result.json[0]["distro_version"] == "7" @@ -112,31 +112,31 @@ def test_filter_by_multiple_distros_with_arch(self, session): assert result.json[1]["distro"] == "ubuntu" assert result.json[1]["distro_codename"] == "xenial" - def test_filter_no_matching_distro(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/search/', params={'distros': 'centos/7'}) + def test_filter_no_matching_distro(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/search/', params={'distros': 'centos/7'}) assert result.json == [] - def test_invalid_distros_query(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get('/api/search/', params={'distros': 'centos7,frufru'}, expect_errors=True) + def test_invalid_distros_query(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get('/api/search/', params={'distros': 'centos7,frufru'}, expect_errors=True) assert "Invalid version or codename for distro: centos7" in result.text class TestLatestSha1(object): - def test_single_repo_is_returned(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get( + def test_single_repo_is_returned(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get( '/api/search/', params={'project': 'ceph', 'sha1': 'latest'}, ) assert result.json[0]['sha1'] == "45107e21c568dd033c2f0a3107dec8f0b0e58374" - def test_one_repo_does_not_match(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(sha1='111000')) - result = session.app.get( + def test_one_repo_does_not_match(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + app.post_json('/api/repos/ceph/', params=base_repo_data(sha1='111000')) + result = app.get( '/api/search/', params={'project': 'ceph', 'sha1': 'latest'}, ) @@ -144,75 +144,75 @@ def test_one_repo_does_not_match(self, session): assert len(result.json) == 1 assert result.json[0]['sha1'] == '111000' - def test_all_repos_match(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(distro_version='trusty')) - result = session.app.get( + def test_all_repos_match(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data()) + app.post_json('/api/repos/ceph/', params=base_repo_data(distro_version='trusty')) + result = app.get( '/api/search/', params={'project': 'ceph', 'sha1': 'latest'}, ) assert len(result.json) == 2 - def test_foo_distinct_repos_match(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(distro='jessie')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data()) - result = session.app.get( + def test_foo_distinct_repos_match(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) + app.post_json('/api/repos/ceph/', params=base_repo_data(distro='jessie')) + app.post_json('/api/repos/ceph/', params=base_repo_data()) + result = app.get( '/api/search/', params={'project': 'ceph', 'distros': 'ubuntu/xenial', 'sha1': 'latest'}, ) assert len(result.json) == 1 assert result.json[0]['ref'] == 'jewel' - def test_distinct_repos_match_with_arch(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["x86_64"])) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["arm64"], chacra_url="1")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["foo"], chacra_url="2")) - result = session.app.get( + def test_distinct_repos_match_with_arch(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["x86_64"])) + app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["arm64"], chacra_url="1")) + app.post_json('/api/repos/ceph/', params=base_repo_data(archs=["foo"], chacra_url="2")) + result = app.get( '/api/search/', params={'project': 'ceph', 'distros': 'ubuntu/xenial/x86_64', 'sha1': 'latest'}, ) assert len(result.json) == 1 assert result.json[0]['archs'] == ['x86_64'] - def test_distinct_repos_match_actual_sha1(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(distro='jessie')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(sha1='aaaa')) - result = session.app.get( + def test_distinct_repos_match_actual_sha1(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) + app.post_json('/api/repos/ceph/', params=base_repo_data(distro='jessie')) + app.post_json('/api/repos/ceph/', params=base_repo_data(sha1='aaaa')) + result = app.get( '/api/search/', params={'project': 'ceph', 'distros': 'ubuntu/xenial', 'sha1': 'aaaa'}, ) assert len(result.json) == 1 assert result.json[0]['sha1'] == 'aaaa' - def test_different_distros_match_latest_sha1(self, session): + def test_different_distros_match_latest_sha1(self, app): for sha1 in range(0, 3): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(sha1=str(sha1))) - session.app.post_json( + app.post_json('/api/repos/ceph/', params=base_repo_data(sha1=str(sha1))) + app.post_json( '/api/repos/ceph/', params=base_repo_data( distro='solaris', distro_version='10', sha1=str(sha1)) ) - session.app.post_json( + app.post_json( '/api/repos/ceph/', params=base_repo_data(distro='centos', distro_version='7', sha1=str(sha1)) ) - result = session.app.get( + result = app.get( '/api/search/', params={'project': 'ceph', 'distros': 'ubuntu/xenial,centos/7', 'sha1': 'latest'}, ) assert len(result.json) == 2 assert result.json[0]["sha1"] == '2' - def test_does_not_find_common_sha1_across_distros(self, session): - session.app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(distro='centos', distro_version="7")) - session.app.post_json('/api/repos/ceph/', params=base_repo_data(sha1="aaa")) - result = session.app.get( + def test_does_not_find_common_sha1_across_distros(self, app): + app.post_json('/api/repos/ceph/', params=base_repo_data(ref='master')) + app.post_json('/api/repos/ceph/', params=base_repo_data(distro='centos', distro_version="7")) + app.post_json('/api/repos/ceph/', params=base_repo_data(sha1="aaa")) + result = app.get( '/api/search/', params={'project': 'ceph', 'distros': 'ubuntu/xenial,centos/7', 'sha1': 'latest', 'ref': 'jewel'}, ) diff --git a/shaman/tests/models/test_builds.py b/shaman/tests/models/test_builds.py index f8c5432..86dc7b6 100644 --- a/shaman/tests/models/test_builds.py +++ b/shaman/tests/models/test_builds.py @@ -1,4 +1,4 @@ -from shaman.models import Project, Build +from shaman.models import Project, Build, commit class TestBuild(object): @@ -13,9 +13,9 @@ def setup_method(self): status="failed", ) - def test_can_create(self, session): + def test_can_create(self, app): Build(self.p, **self.data) - session.commit() + commit() b = Build.get(1) assert b.ref == "master" assert b.sha1 == "sha1" @@ -24,36 +24,36 @@ def test_can_create(self, session): assert b.build_id == "250" assert b.status == "failed" - def test_distro_can_be_null(self, session): + def test_distro_can_be_null(self, app): Build(self.p, **self.data) - session.commit() + commit() b = Build.get(1) assert not b.distro - def test_distro_version_can_be_null(self, session): + def test_distro_version_can_be_null(self, app): Build(self.p, **self.data) - session.commit() + commit() b = Build.get(1) assert not b.distro_version - def test_can_create_with_extra(self, session): + def test_can_create_with_extra(self, app): b = Build(self.p, **self.data) b.extra = dict(version="10.2.2") - session.commit() + commit() build = Build.get(1) assert build.extra['version'] == "10.2.2" - def test_sets_modified(self, session): + def test_sets_modified(self, app): build = Build(self.p, **self.data) - session.commit() + commit() assert build.modified.timetuple() - def test_update_changes_modified(self, session): + def test_update_changes_modified(self, app): build = Build(self.p, **self.data) initial_timestamp = build.modified.time() - session.commit() + commit() build.distro = "centos" - session.commit() + commit() assert initial_timestamp < build.modified.time() @@ -70,26 +70,26 @@ def setup_method(self): status="failed", ) - def test_default_gives_full_url(self, session): + def test_default_gives_full_url(self, app): Build(self.p, **self.data) - session.commit() + commit() result = Build.get(1).get_url() assert result == '/builds/ceph/master/sha1/default/1/' - def test_by_ref(self, session): + def test_by_ref(self, app): build = Build(self.p, **self.data) - session.commit() + commit() result = build.get_url('ref') assert result == '/builds/ceph/master/' - def test_by_sha1(self, session): + def test_by_sha1(self, app): build = Build(self.p, **self.data) - session.commit() + commit() result = build.get_url('sha1') assert result == '/builds/ceph/master/sha1/' - def test_up_to_project(self, session): + def test_up_to_project(self, app): build = Build(self.p, **self.data) - session.commit() + commit() result = build.get_url('project') assert result == '/builds/ceph/' diff --git a/shaman/tests/models/test_repos.py b/shaman/tests/models/test_repos.py index 29d3fec..8e9df1e 100644 --- a/shaman/tests/models/test_repos.py +++ b/shaman/tests/models/test_repos.py @@ -1,4 +1,4 @@ -from shaman.models import Repo, Project, Arch +from shaman.models import Repo, Project, Arch, commit class TestRepo(object): @@ -10,57 +10,57 @@ def setup_method(self): distro_version="trusty", ) - def test_can_create(self, session): + def test_can_create(self, app): Repo(self.p, **self.data) - session.commit() + commit() repo = Repo.get(1) assert repo.project.name == "ceph" assert repo.distro == "ubuntu" assert repo.distro_version == "trusty" assert repo.flavor == "default" - def test_can_create_with_extra(self, session): + def test_can_create_with_extra(self, app): r = Repo(self.p, **self.data) r.extra = dict(version="10.2.2") - session.commit() + commit() repo = Repo.get(1) assert repo.extra['version'] == "10.2.2" - def test_sets_modified(self, session): + def test_sets_modified(self, app): repo = Repo(self.p, **self.data) - session.commit() + commit() assert repo.modified.timetuple() - def test_update_changes_modified(self, session): + def test_update_changes_modified(self, app): repo = Repo(self.p, **self.data) initial_timestamp = repo.modified.time() - session.commit() + commit() repo.distro = "centos" - session.commit() + commit() assert initial_timestamp < repo.modified.time() - def test_can_create_with_arch(self, session): + def test_can_create_with_arch(self, app): repo = Repo(self.p, **self.data) arch = Arch(name="x86_64", repo=repo) - session.commit() + commit() repo = Repo.get(1) assert arch in repo.archs - def test_can_create_with_many_archs(self, session): + def test_can_create_with_many_archs(self, app): repo = Repo(self.p, **self.data) arch1 = Arch(name="x86_64", repo=repo) arch2 = Arch(name="arm64", repo=repo) - session.commit() + commit() repo = Repo.get(1) assert arch1 in repo.archs assert arch2 in repo.archs - def test_delete_will_delete_arch(self, session): + def test_delete_will_delete_arch(self, app): repo = Repo(self.p, **self.data) Arch(name="x86_64", repo=repo) - session.commit() + commit() repo = Repo.get(1) repo.delete() - session.commit() + commit() assert not Repo.query.first() assert not Arch.query.first() diff --git a/shaman/tests/test_util.py b/shaman/tests/test_util.py index 1f5408f..c5503cf 100644 --- a/shaman/tests/test_util.py +++ b/shaman/tests/test_util.py @@ -3,7 +3,7 @@ from requests.exceptions import BaseHTTPError, RequestException from shaman import util -from shaman.models import Node, Repo, Project, Arch +from shaman.models import Node, Repo, Project, Arch, commit import pytest from mock import patch @@ -12,35 +12,35 @@ class TestIsNodeHealthy(object): @patch("shaman.util.requests.get") - def test_node_is_healthy(self, m_get, session): + def test_node_is_healthy(self, m_get, app): m_get.return_value.ok = True node = Node("chacra.ceph.com") - session.commit() + commit() assert util.is_node_healthy(node) @patch("shaman.util.requests.get") - def test_last_check_is_updated(self, m_get, session): + def test_last_check_is_updated(self, m_get, app): m_get.return_value.ok = True node = Node("chacra.ceph.com") last_check = datetime.datetime.now() node.last_check = datetime.datetime.now() - session.commit() + commit() util.is_node_healthy(node) node = Node.get(1) assert node.last_check.time() > last_check.time() @patch("shaman.util.requests.get") - def test_down_count_is_cleared_when_healthy(self, m_get, session): + def test_down_count_is_cleared_when_healthy(self, m_get, app): m_get.return_value.ok = True node = Node("chacra.ceph.com") node.down_count = 2 - session.commit() + commit() util.is_node_healthy(node) node = Node.get(1) assert node.down_count == 0 @patch("shaman.util.requests.get") - def test_healthy_is_true_when_rejoining_pool(self, m_get, session): + def test_healthy_is_true_when_rejoining_pool(self, m_get, app): """ Tests the scenario where a node has been marked down, but is now up again and needs to rejoin the pool. @@ -49,34 +49,34 @@ def test_healthy_is_true_when_rejoining_pool(self, m_get, session): node = Node("chacra.ceph.com") node.down_count = 3 node.healthy = False - session.commit() + commit() util.is_node_healthy(node) node = Node.get(1) assert node.down_count == 0 assert node.healthy @patch("shaman.util.requests.get") - def test_node_is_not_healthy(self, m_get, session): + def test_node_is_not_healthy(self, m_get, app): m_get.return_value.ok = False node = Node("chacra.ceph.com") - session.commit() + commit() assert not util.is_node_healthy(node) @patch("shaman.util.requests.get") - def test_down_count_is_incremented(self, m_get, session): + def test_down_count_is_incremented(self, m_get, app): m_get.return_value.ok = False node = Node("chacra.ceph.com") - session.commit() + commit() util.is_node_healthy(node) node = Node.get(1) assert node.down_count == 1 @patch("shaman.util.requests.get") - def test_node_exceeds_down_count_limit(self, m_get, session): + def test_node_exceeds_down_count_limit(self, m_get, app): m_get.return_value.ok = False node = Node("chacra.ceph.com") node.down_count = 2 - session.commit() + commit() util.is_node_healthy(node) node = Node.get(1) assert not node.healthy @@ -94,20 +94,20 @@ def request_exception(exc=RequestException): class TestCheckNodeHealth(object): - def test_healthy(self, session, monkeypatch): + def test_healthy(self, monkeypatch, app): response = RequestsResponse() monkeypatch.setattr(requests, "get", lambda *a, **kw: response) healthy = util.check_node_health(Node("chacra.ceph.com")) assert healthy is True - def test_unhealthy(self, session, monkeypatch): + def test_unhealthy(self, monkeypatch, app): response = RequestsResponse(ok=False) monkeypatch.setattr(requests, "get", lambda *a, **kw: response) healthy = util.check_node_health(Node("chacra.ceph.com")) assert healthy is False @pytest.mark.parametrize('exc', [BaseHTTPError, RequestException]) - def test_node_raises_requests_exception(self, exc, session, monkeypatch): + def test_node_raises_requests_exception(self, exc, monkeypatch, app): monkeypatch.setattr(requests, "get", lambda *a, **kw: request_exception(exc)) healthy = util.check_node_health(Node("chacra.ceph.com")) assert healthy is False @@ -115,45 +115,45 @@ def test_node_raises_requests_exception(self, exc, session, monkeypatch): class TestGetNextNode(object): - def test_no_nodes(self, session): + def test_no_nodes(self, app): assert not util.get_next_node() - def test_finds_a_node(self, session, monkeypatch): + def test_finds_a_node(self, monkeypatch, app): monkeypatch.setattr(util, "is_node_healthy", lambda node: True) node = Node("chacra.ceph.com") - session.commit() + commit() next_node = util.get_next_node() assert next_node == node - def test_sets_last_used_on_selection(self, session, monkeypatch): + def test_sets_last_used_on_selection(self, monkeypatch, app): monkeypatch.setattr(util, "is_node_healthy", lambda node: True) node = Node("chacra.ceph.com") - session.commit() + commit() last_used = node.last_used next_node = util.get_next_node() assert next_node.last_used.time() > last_used.time() - def test_no_healthy_nodes(self, session): + def test_no_healthy_nodes(self, app): node = Node("chacra.ceph.com") node.healthy = False - session.commit() + commit() assert not util.get_next_node() - def test_use_newly_added_node(self, session, monkeypatch): + def test_use_newly_added_node(self, monkeypatch, app): monkeypatch.setattr(util, "is_node_healthy", lambda node: True) n1 = Node("chacra01.ceph.com") n1.last_used = datetime.datetime.now() n2 = Node("chacra02.ceph.com") - session.commit() + commit() assert n2 == util.get_next_node() - def test_pick_last_used_node(self, session, monkeypatch): + def test_pick_last_used_node(self, monkeypatch, app): monkeypatch.setattr(util, "is_node_healthy", lambda node: True) n1 = Node("chacra01.ceph.com") n1.last_used = datetime.datetime.now() - datetime.timedelta(days=1) n2 = Node("chacra02.ceph.com") n2.last_used = datetime.datetime.now() - session.commit() + commit() assert n1 == util.get_next_node() @@ -274,44 +274,50 @@ def base_repo_data(**kw): class TestGetRepoUrl(object): - def setup_method(self): + def add_repo(self): self.p = Project("ceph") self.data = base_repo_data() self.repo = Repo(self.p, **self.data) Arch(name="x86_64", repo=self.repo) - def test_repo_file_is_true(self, session): - session.commit() + def test_repo_file_is_true(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='ready') result = util.get_repo_url(query, 'x86_64', repo_file=True) assert result.endswith("/repo") - def test_repo_file_is_false(self, session): - session.commit() + def test_repo_file_is_false(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='ready') result = util.get_repo_url(query, 'x86_64', repo_file=False) assert result.startswith("chacra.ceph.com/r/") - def test_arch_is_none(self, session): - session.commit() + def test_arch_is_none(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='ready') result = util.get_repo_url(query, None, repo_file=False) assert result.startswith("chacra.ceph.com/r/") - def test_repo_not_found(self, session): - session.commit() + def test_repo_not_found(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='queued') result = util.get_repo_url(query, None, repo_file=False) assert not result - def test_redirect_to_a_directory(self, session): - session.commit() + def test_redirect_to_a_directory(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='ready') result = util.get_repo_url(query, 'x86_64', path=["SRPMS"], repo_file=False) assert result.endswith("/SRPMS") - def test_redirect_to_a_directory_path(self, session): - session.commit() + def test_redirect_to_a_directory_path(self, app): + self.add_repo() + commit() query = Repo.query.filter_by(status='ready') result = util.get_repo_url(query, 'x86_64', path=["SRPMS", "repodata", "repomd.xml"], repo_file=False) assert result.endswith("/SRPMS/repodata/repomd.xml") From 43893fad8e02fd05b08a9cd8d5853b2a2ca0aa5d Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Mon, 31 Mar 2025 15:02:01 -0600 Subject: [PATCH 06/10] templates.helpers.last_seen: Add UTC timezone This looks to be necessary to support sqlite. Signed-off-by: Zack Cerza --- shaman/templates/helpers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shaman/templates/helpers.py b/shaman/templates/helpers.py index 6ca5be4..622ac5b 100644 --- a/shaman/templates/helpers.py +++ b/shaman/templates/helpers.py @@ -3,7 +3,7 @@ def last_seen(date_object): now = datetime.now(timezone.utc) - difference = now - date_object + difference = now - date_object.astimezone(timezone.utc) formatted = ReadableSeconds(difference.seconds, days=difference.days) return "%s ago" % formatted From c5fe43894aa2769baff9aa533f7f8efab4c99372 Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Mon, 31 Mar 2025 15:02:07 -0600 Subject: [PATCH 07/10] models: Disable sqlite synchronous mode It could mask bugs, and is a little slower. Signed-off-by: Zack Cerza --- shaman/models/__init__.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shaman/models/__init__.py b/shaman/models/__init__.py index 66a0843..cf9a72c 100644 --- a/shaman/models/__init__.py +++ b/shaman/models/__init__.py @@ -3,6 +3,7 @@ from sqlalchemy import create_engine, MetaData, event from sqlalchemy.orm import scoped_session, sessionmaker, object_session, mapper from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.pool import Pool from pecan import conf @@ -116,6 +117,8 @@ def init_model(): """ conf.sqlalchemy_w.engine = _engine_from_config(conf.sqlalchemy_w) conf.sqlalchemy_ro.engine = _engine_from_config(conf.sqlalchemy_ro) + if 'sqlite' in dict(conf)['sqlalchemy_w']['url']: + event.listen(Pool, 'connect', sqlite_connect, named=True) def _engine_from_config(configuration): @@ -124,6 +127,12 @@ def _engine_from_config(configuration): return create_engine(url, **configuration) +def sqlite_connect(**kw): + dbapi_con = kw['dbapi_connection'] + dbapi_con.execute('PRAGMA journal_mode=MEMORY') + dbapi_con.execute('PRAGMA synchronous=OFF') + + def start(): Session.bind = conf.sqlalchemy_w.engine metadata.bind = conf.sqlalchemy_w.engine From 5f1de935e3851d4f74c303c12ec6968595467fd9 Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Tue, 1 Apr 2025 12:53:24 -0600 Subject: [PATCH 08/10] tox: Don't hardcode test dependencies Signed-off-by: Zack Cerza --- tox.ini | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tox.ini b/tox.ini index d3fafed..f260911 100644 --- a/tox.ini +++ b/tox.ini @@ -3,9 +3,7 @@ envlist = py3, flake8 [testenv] deps= - pytest - webtest - mock + [test] commands=pytest -v {posargs:shaman/tests} [testenv:flake8] From f811a77e7cb6fcbde332aed261a6a35f90f2a1d9 Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Tue, 1 Apr 2025 13:10:28 -0600 Subject: [PATCH 09/10] tox: Add separate testenv for postgres Signed-off-by: Zack Cerza --- tox.ini | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f260911..472b71c 100644 --- a/tox.ini +++ b/tox.ini @@ -1,11 +1,14 @@ [tox] -envlist = py3, flake8 +envlist = flake8, sqlite [testenv] deps= [test] commands=pytest -v {posargs:shaman/tests} +[testenv:postgres] +commands=pytest -v --db-url 'postgresql+psycopg2://postgres@localhost:5432/shamantest' {posargs:shaman/tests} + [testenv:flake8] deps=flake8 commands=flake8 --select=F,E9 {posargs:shaman} From 6b0b224df0354f13de97d5b74d8d2a370136050d Mon Sep 17 00:00:00 2001 From: Zack Cerza Date: Tue, 1 Apr 2025 13:13:34 -0600 Subject: [PATCH 10/10] CI: Split into sqlite/posgres Signed-off-by: Zack Cerza --- .github/workflows/{ci.yml => postgres.yml} | 19 +++++++-------- .github/workflows/sqlite.yml | 27 ++++++++++++++++++++++ 2 files changed, 35 insertions(+), 11 deletions(-) rename .github/workflows/{ci.yml => postgres.yml} (76%) create mode 100644 .github/workflows/sqlite.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/postgres.yml similarity index 76% rename from .github/workflows/ci.yml rename to .github/workflows/postgres.yml index 8e61cf4..49a8ffb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/postgres.yml @@ -1,33 +1,28 @@ -name: ci +name: postgres on: pull_request: branches: - main - - test workflow_dispatch: jobs: test: name: CI on python${{ matrix.python }} via ${{ matrix.os }} - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest strategy: matrix: include: - - os: ubuntu-22.04 - python: "3.10" - - os: ubuntu-22.04 - python: "3.11" - - os: ubuntu-24.04 - python: "3.12" + - python: "3.10" + - python: "3.13" steps: - uses: actions/checkout@v4 - name: Setup Python uses: actions/setup-python@v5 with: python-version: ${{ matrix.python }} - - name: Install tox - run: pip install tox + - name: Install uv + uses: astral-sh/setup-uv@v5 - name: Install postgresql run: | sudo apt-get install -y postgresql @@ -41,3 +36,5 @@ jobs: pg_isready - name: Run unit tests run: tox -e py3 + - name: Run tox + run: uv tool run tox -e postgresql diff --git a/.github/workflows/sqlite.yml b/.github/workflows/sqlite.yml new file mode 100644 index 0000000..d8723e0 --- /dev/null +++ b/.github/workflows/sqlite.yml @@ -0,0 +1,27 @@ +name: sqlite + +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + test: + name: CI on python${{ matrix.python }} via ${{ matrix.os }} + runs-on: ubuntu-latest + strategy: + matrix: + include: + - python: "3.10" + - python: "3.13" + steps: + - uses: actions/checkout@v4 + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python }} + - name: Install uv + uses: astral-sh/setup-uv@v5 + - name: Run tox + run: uv tool run tox