From b21b6db4487b5f349cb37018c5aaf282d1739b6c Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 19 Jun 2025 16:15:15 -0300 Subject: [PATCH 1/5] adjust project config to use UV --- antithesis-tests/pyproject.toml | 12 ++ pyproject.toml | 2 +- uv.lock | 218 ++++++++++++++++++++++++++++++++ 3 files changed, 231 insertions(+), 1 deletion(-) create mode 100644 antithesis-tests/pyproject.toml diff --git a/antithesis-tests/pyproject.toml b/antithesis-tests/pyproject.toml new file mode 100644 index 000000000..be471123d --- /dev/null +++ b/antithesis-tests/pyproject.toml @@ -0,0 +1,12 @@ +[project] +dependencies = [ + "antithesis>=0.1.17", + "pylimbo" +] +description = "Add your description here" +name = "antithesis-tests" +requires-python = ">=3.13" +version = "0.1.0" + +[tool.uv.sources] +pylimbo = { workspace = true } diff --git a/pyproject.toml b/pyproject.toml index b652f9f25..4e069035c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,4 +14,4 @@ package = false limbo_test = { workspace = true } [tool.uv.workspace] -members = ["testing", "scripts"] +members = ["testing", "scripts", "antithesis-tests", "bindings/python"] diff --git a/uv.lock b/uv.lock index 7c6a5bc43..d4b2db9d5 100644 --- a/uv.lock +++ b/uv.lock @@ -1,10 +1,13 @@ version = 1 +revision = 1 requires-python = ">=3.13" [manifest] members = [ + "antithesis-tests", "limbo", "limbo-test", + "pylimbo", "scripts", ] @@ -17,6 +20,33 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643 }, ] +[[package]] +name = "antithesis" +version = "0.1.17" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fe/cb/162e6392d43263b27577a6d50a2f0338cc22424e36a6beee9a2c09c1220c/antithesis-0.1.17.tar.gz", hash = "sha256:5083676ef84d3b424188056c0c5cf3db584c1e0604338a7e6b34d265caaf801e", size = 15427 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/73/58/49eef5d79d6b34a90b7a910fceb949c9964857173d1ada85d4c8772c978e/antithesis-0.1.17-py3-none-any.whl", hash = "sha256:0fe7ef78e7a9ea5f9b4b5a1b855c10d79863e7f08b484a29a4b1d599b9a43794", size = 15972 }, +] + +[[package]] +name = "antithesis-tests" +version = "0.1.0" +source = { virtual = "antithesis-tests" } +dependencies = [ + { name = "antithesis" }, + { name = "pylimbo" }, +] + +[package.metadata] +requires-dist = [ + { name = "antithesis", specifier = ">=0.1.17" }, + { name = "pylimbo", editable = "bindings/python" }, +] + [[package]] name = "certifi" version = "2025.1.31" @@ -70,6 +100,43 @@ wheels = [ { 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 = "coverage" +version = "7.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/08/7e37f82e4d1aead42a7443ff06a1e406aabf7302c4f00a546e4b320b994c/coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d", size = 798791 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/f9/9aa4dfb751cb01c949c990d136a0f92027fbcc5781c6e921df1cb1563f20/coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106", size = 207007 }, + { url = "https://files.pythonhosted.org/packages/b9/67/e1413d5a8591622a46dd04ff80873b04c849268831ed5c304c16433e7e30/coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9", size = 207269 }, + { url = "https://files.pythonhosted.org/packages/14/5b/9dec847b305e44a5634d0fb8498d135ab1d88330482b74065fcec0622224/coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c", size = 239886 }, + { url = "https://files.pythonhosted.org/packages/7b/b7/35760a67c168e29f454928f51f970342d23cf75a2bb0323e0f07334c85f3/coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a", size = 237037 }, + { url = "https://files.pythonhosted.org/packages/f7/95/d2fd31f1d638df806cae59d7daea5abf2b15b5234016a5ebb502c2f3f7ee/coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060", size = 239038 }, + { url = "https://files.pythonhosted.org/packages/6e/bd/110689ff5752b67924efd5e2aedf5190cbbe245fc81b8dec1abaffba619d/coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862", size = 238690 }, + { url = "https://files.pythonhosted.org/packages/d3/a8/08d7b38e6ff8df52331c83130d0ab92d9c9a8b5462f9e99c9f051a4ae206/coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388", size = 236765 }, + { url = "https://files.pythonhosted.org/packages/d6/6a/9cf96839d3147d55ae713eb2d877f4d777e7dc5ba2bce227167d0118dfe8/coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155", size = 238611 }, + { url = "https://files.pythonhosted.org/packages/74/e4/7ff20d6a0b59eeaab40b3140a71e38cf52547ba21dbcf1d79c5a32bba61b/coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a", size = 209671 }, + { url = "https://files.pythonhosted.org/packages/35/59/1812f08a85b57c9fdb6d0b383d779e47b6f643bc278ed682859512517e83/coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129", size = 210368 }, + { url = "https://files.pythonhosted.org/packages/9c/15/08913be1c59d7562a3e39fce20661a98c0a3f59d5754312899acc6cb8a2d/coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e", size = 207758 }, + { url = "https://files.pythonhosted.org/packages/c4/ae/b5d58dff26cade02ada6ca612a76447acd69dccdbb3a478e9e088eb3d4b9/coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962", size = 208035 }, + { url = "https://files.pythonhosted.org/packages/b8/d7/62095e355ec0613b08dfb19206ce3033a0eedb6f4a67af5ed267a8800642/coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb", size = 250839 }, + { url = "https://files.pythonhosted.org/packages/7c/1e/c2967cb7991b112ba3766df0d9c21de46b476d103e32bb401b1b2adf3380/coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704", size = 246569 }, + { url = "https://files.pythonhosted.org/packages/8b/61/a7a6a55dd266007ed3b1df7a3386a0d760d014542d72f7c2c6938483b7bd/coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b", size = 248927 }, + { url = "https://files.pythonhosted.org/packages/c8/fa/13a6f56d72b429f56ef612eb3bc5ce1b75b7ee12864b3bd12526ab794847/coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f", size = 248401 }, + { url = "https://files.pythonhosted.org/packages/75/06/0429c652aa0fb761fc60e8c6b291338c9173c6aa0f4e40e1902345b42830/coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223", size = 246301 }, + { url = "https://files.pythonhosted.org/packages/52/76/1766bb8b803a88f93c3a2d07e30ffa359467810e5cbc68e375ebe6906efb/coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3", size = 247598 }, + { url = "https://files.pythonhosted.org/packages/66/8b/f54f8db2ae17188be9566e8166ac6df105c1c611e25da755738025708d54/coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f", size = 210307 }, + { url = "https://files.pythonhosted.org/packages/9f/b0/e0dca6da9170aefc07515cce067b97178cefafb512d00a87a1c717d2efd5/coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657", size = 211453 }, +] + [[package]] name = "cryptography" version = "44.0.2" @@ -138,6 +205,15 @@ 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 = "limbo" version = "0.1.0" @@ -176,6 +252,26 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528 }, ] +[[package]] +name = "maturin" +version = "1.7.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ab/1e/085ddc0e5b08ae7af7a743a0dd6ed06b22a1332288488f1a333137885150/maturin-1.7.8.tar.gz", hash = "sha256:649c6ef3f0fa4c5f596140d761dc5a4d577c485cc32fb5b9b344a8280352880d", size = 195704 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/ed/c8bb26e91c879e418ae1b01630722ed20b6fe0e6755be8d538d83666f136/maturin-1.7.8-py3-none-linux_armv6l.whl", hash = "sha256:c6950fd2790acd93265e1501cea66f9249cff19724654424ca75a3b17ebb315b", size = 7515691 }, + { url = "https://files.pythonhosted.org/packages/38/7a/573f969315f0b92a09a0a565d45e98812c87796e2e19a7856159ab234faf/maturin-1.7.8-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:f98288d5c382bacf0c076871dfd50c38f1eb2248f417551e98dd6f47f6ee8afa", size = 14434454 }, + { url = "https://files.pythonhosted.org/packages/a6/17/46834841fbf19231487f185e68b95ca348cc05cce49be8787e0bc7e9dc47/maturin-1.7.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b2d4e0f674ca29864e6b86c2eb9fee8236d1c7496c25f7300e34229272468f4c", size = 7509122 }, + { url = "https://files.pythonhosted.org/packages/c1/8f/bf8b4871eb390a4baef2e0bb5016852c7c0311a9772e2945534cfa2ee40e/maturin-1.7.8-py3-none-manylinux_2_12_i686.manylinux2010_i686.musllinux_1_1_i686.whl", hash = "sha256:6cafb17bf57822bdc04423d9e3e766d42918d474848fe9833e397267514ba891", size = 7598870 }, + { url = "https://files.pythonhosted.org/packages/dc/43/c842be67a7c59568082345249b956138ae93d0b2474fb41c186ce26d05e1/maturin-1.7.8-py3-none-manylinux_2_12_x86_64.manylinux2010_x86_64.musllinux_1_1_x86_64.whl", hash = "sha256:2b2bdee0c3a84696b3a809054c43ead1a04b7b3321cbd5b8f5676e4ba4691d0f", size = 7932310 }, + { url = "https://files.pythonhosted.org/packages/12/12/42435d05f2d6c75eb621751e6f021d29eb34d18e3b9c5c94d828744c2d54/maturin-1.7.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.musllinux_1_1_aarch64.whl", hash = "sha256:b8188b71259fc2bc568d9c8acc186fcfed96f42539bcb55b8e6f4ec26e411f37", size = 7321964 }, + { url = "https://files.pythonhosted.org/packages/b4/26/f3272ee985ebf9b3e8c4cd4f4efb022af1e12c9f53aed0dcc9a255399f4e/maturin-1.7.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.musllinux_1_1_armv7l.whl", hash = "sha256:a4f58c2a53c2958a1bf090960b08b28e676136cd88ac2f5dfdcf1b14ea54ec06", size = 7408613 }, + { url = "https://files.pythonhosted.org/packages/36/7d/be27bcc7d3ac6e6c2136a8ec0cc56f227a292d6cfdde55e095b6c0aa24a9/maturin-1.7.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.musllinux_1_1_ppc64le.whl", hash = "sha256:c5d6c0c631d1fc646cd3834795e6cfd72ab4271d289df7e0f911261a02bec75f", size = 9496974 }, + { url = "https://files.pythonhosted.org/packages/e1/e8/0d7323e9a31c11edf69c4473d73eca74803ce3e2390abf8ae3ac7eb10b04/maturin-1.7.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c23664d19dadcbf800ef70f26afb2e0485a985c62889930934f019c565534c23", size = 10828401 }, + { url = "https://files.pythonhosted.org/packages/7e/82/5080e052c0d8c9872f6d4b94cae84c17ed7f2ea270d709210ea6445b655f/maturin-1.7.8-py3-none-win32.whl", hash = "sha256:403eebf1afa6f19b49425f089e39c53b8e597bc86a47f3a76e828dc78d27fa80", size = 6845240 }, + { url = "https://files.pythonhosted.org/packages/6d/c9/9b162361ded893f36038c2f8ac6a972ec441c11df8d17c440997eb28090f/maturin-1.7.8-py3-none-win_amd64.whl", hash = "sha256:1ce48d007438b895f8665314b6748ac0dab31e4f32049a60b52281dd2dccbdde", size = 7762332 }, + { url = "https://files.pythonhosted.org/packages/fa/40/46d4742db742f69a7fe0054cd7c82bc79b2d70cb8c91f7e737e75c28a5f3/maturin-1.7.8-py3-none-win_arm64.whl", hash = "sha256:cc92a62953205e8945b6cfe6943d6a8576a4442d30d9c67141f944f4f4640e62", size = 6501353 }, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -185,6 +281,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979 }, ] +[[package]] +name = "mypy" +version = "1.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mypy-extensions" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/95/a6dbb4fef19402c488b001ff4bd9f1a770e44049ce049b904dcffc65356c/mypy-1.11.0.tar.gz", hash = "sha256:93743608c7348772fdc717af4aeee1997293a1ad04bc0ea6efa15bf65385c538", size = 3078260 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/0e/fc28db5d225623cbbca54d9f4207a3ebf4937d816ba4b61aa3a5ad2af2e7/mypy-1.11.0-py3-none-any.whl", hash = "sha256:56913ec8c7638b0091ef4da6fcc9136896914a9d60d54670a75880c3e5b99ace", size = 2619149 }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963 }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469 }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538 }, +] + [[package]] name = "pycparser" version = "2.22" @@ -277,6 +413,35 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pylimbo" +source = { editable = "bindings/python" } +dependencies = [ + { name = "typing-extensions" }, +] + +[package.optional-dependencies] +dev = [ + { name = "coverage" }, + { name = "maturin" }, + { name = "mypy" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "coverage", marker = "extra == 'dev'", specifier = "==7.6.1" }, + { name = "maturin", marker = "extra == 'dev'", specifier = "==1.7.8" }, + { name = "mypy", marker = "extra == 'dev'", specifier = "==1.11.0" }, + { name = "pytest", marker = "extra == 'dev'", specifier = "==8.3.1" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = "==5.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = "==0.5.4" }, + { name = "typing-extensions", specifier = ">=4.6.0,!=4.7.0" }, +] +provides-extras = ["dev"] + [[package]] name = "pynacl" version = "1.5.0" @@ -297,6 +462,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/22/d3db169895faaf3e2eda892f005f433a62db2decbcfbc2f61e6517adfa87/PyNaCl-1.5.0-cp36-abi3-win_amd64.whl", hash = "sha256:20f42270d27e1b6a29f54032090b972d97f0a1b0948cc52392041ef7831fee93", size = 212141 }, ] +[[package]] +name = "pytest" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bc/7f/a6f79e033aa8318b6dfe2173fa6409ee75dafccf409d90884bf921433d88/pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6", size = 1438997 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/77/ccea391104f576a6e54a54334fc26d29c28aa0ec85714c781fbd2c34ac86/pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c", size = 341628 }, +] + +[[package]] +name = "pytest-cov" +version = "5.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/67/00efc8d11b630c56f15f4ad9c7f9223f1e5ec275aaae3fa9118c6a223ad2/pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857", size = 63042 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/3a/af5b4fa5961d9a1e6237b530eb87dd04aea6eb83da09d2a4073d81b54ccf/pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652", size = 21990 }, +] + [[package]] name = "requests" version = "2.32.3" @@ -325,6 +518,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229 }, ] +[[package]] +name = "ruff" +version = "0.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/1a/5955fa22ab088c1f4d8458b4cbc158c6db72143361e8d46e179c48576aab/ruff-0.5.4.tar.gz", hash = "sha256:2795726d5f71c4f4e70653273d1c23a8182f07dd8e48c12de5d867bfb7557eed", size = 2424702 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/34/2235ecce6794345f42ad334d1b14384c70b202f77509e5678b68a640fe78/ruff-0.5.4-py3-none-linux_armv6l.whl", hash = "sha256:82acef724fc639699b4d3177ed5cc14c2a5aacd92edd578a9e846d5b5ec18ddf", size = 9499774 }, + { url = "https://files.pythonhosted.org/packages/11/23/ffe51028ba274223191d3f96b059108cf7690eb93985a7fdb077c3d1191b/ruff-0.5.4-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:da62e87637c8838b325e65beee485f71eb36202ce8e3cdbc24b9fcb8b99a37be", size = 8550240 }, + { url = "https://files.pythonhosted.org/packages/28/75/843aa3d10a39ab60fbd63f65c825f647907a9732ac27e24d3f94dd2db618/ruff-0.5.4-py3-none-macosx_11_0_arm64.whl", hash = "sha256:e98ad088edfe2f3b85a925ee96da652028f093d6b9b56b76fc242d8abb8e2059", size = 8160520 }, + { url = "https://files.pythonhosted.org/packages/19/88/3d0f5244905088cc2fd136fae8ce81f46d145e2449051313c462032d144d/ruff-0.5.4-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c55efbecc3152d614cfe6c2247a3054cfe358cefbf794f8c79c8575456efe19", size = 9911606 }, + { url = "https://files.pythonhosted.org/packages/1f/ff/6546020836408351e7558dedacc6e5ca7f652f76a9d05ac4882c787d45b1/ruff-0.5.4-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9b85eaa1f653abd0a70603b8b7008d9e00c9fa1bbd0bf40dad3f0c0bdd06793", size = 9286353 }, + { url = "https://files.pythonhosted.org/packages/b6/bf/51e0c5f12a9bf3c7596cf7f45e1b102f8b49f1da39943e03739890bbf6a4/ruff-0.5.4-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0cf497a47751be8c883059c4613ba2f50dd06ec672692de2811f039432875278", size = 10082929 }, + { url = "https://files.pythonhosted.org/packages/b5/0e/a44cb6edb629788de892fc7bb8ac8b47059df94d7ec9c4e52e04bab5be95/ruff-0.5.4-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:09c14ed6a72af9ccc8d2e313d7acf7037f0faff43cde4b507e66f14e812e37f7", size = 10832586 }, + { url = "https://files.pythonhosted.org/packages/97/ca/e3810f701ae472e5fe3180d56fe6fcc92ea94c7490097a0f731f5602f26f/ruff-0.5.4-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:628f6b8f97b8bad2490240aa84f3e68f390e13fabc9af5c0d3b96b485921cd60", size = 10421967 }, + { url = "https://files.pythonhosted.org/packages/01/47/a62df6ccd6e5d019271df203ea6564f2022c49f85c0bf6ada708cd7b4a5e/ruff-0.5.4-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3520a00c0563d7a7a7c324ad7e2cde2355733dafa9592c671fb2e9e3cd8194c1", size = 11371031 }, + { url = "https://files.pythonhosted.org/packages/a1/02/64f24893eea23c447460e6509e9dd0ae18d7a797f67fee1bafed964ebbae/ruff-0.5.4-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93789f14ca2244fb91ed481456f6d0bb8af1f75a330e133b67d08f06ad85b516", size = 10103164 }, + { url = "https://files.pythonhosted.org/packages/ca/78/683b6c6976fcc33e4a03a0e234e0b9f9b8682f807a661225c829b248de82/ruff-0.5.4-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:029454e2824eafa25b9df46882f7f7844d36fd8ce51c1b7f6d97e2615a57bbcc", size = 9920056 }, + { url = "https://files.pythonhosted.org/packages/78/3a/6c67c5d670aae2a51a11713aff819d729ed92cb0b1d962b8df27e4657650/ruff-0.5.4-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9492320eed573a13a0bc09a2957f17aa733fff9ce5bf00e66e6d4a88ec33813f", size = 9361286 }, + { url = "https://files.pythonhosted.org/packages/0d/f5/da3a0e2fd0bcbdb3d2ff579ef9cb3ca2af71b9bee97fa917c9a9e0500b67/ruff-0.5.4-py3-none-musllinux_1_2_i686.whl", hash = "sha256:a6e1f62a92c645e2919b65c02e79d1f61e78a58eddaebca6c23659e7c7cb4ac7", size = 9720829 }, + { url = "https://files.pythonhosted.org/packages/4a/56/5062119a5c9e06d98cd6406bfc1eab7616a7c67494a4d05b6052d99dd147/ruff-0.5.4-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:768fa9208df2bec4b2ce61dbc7c2ddd6b1be9fb48f1f8d3b78b3332c7d71c1ff", size = 10143530 }, + { url = "https://files.pythonhosted.org/packages/e6/76/16f8f1c8d0cba6c96ab6f292146fc0acb6dd633a989f524d3b3ef1ee8364/ruff-0.5.4-py3-none-win32.whl", hash = "sha256:e1e7393e9c56128e870b233c82ceb42164966f25b30f68acbb24ed69ce9c3a4e", size = 7794271 }, + { url = "https://files.pythonhosted.org/packages/82/35/d6c3c83fb8817328db73c15b1836ccb0c3ce56b72d0d01d98b3a452bec58/ruff-0.5.4-py3-none-win_amd64.whl", hash = "sha256:58b54459221fd3f661a7329f177f091eb35cf7a603f01d9eb3eb11cc348d38c4", size = 8579021 }, + { url = "https://files.pythonhosted.org/packages/3c/ef/3e732c0152280775f728ab99691c718ee9a4ae79bf5af1dd9258f7fe7fef/ruff-0.5.4-py3-none-win_arm64.whl", hash = "sha256:bd53da65f1085fb5b307c38fd3c0829e76acf7b2a912d8d79cadcdb4875c1eb7", size = 8034239 }, +] + [[package]] name = "scripts" version = "0.1.0" From 46135e43ce060f4d65282dc086ba11062f7d460c Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 19 Jun 2025 16:37:49 -0300 Subject: [PATCH 2/5] use uv in github actions --- .github/workflows/python.yml | 51 ++++++++++------------------------ bindings/python/pyproject.toml | 14 ++++++++++ uv.lock | 28 +++++++++++++++++++ 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 20b0d961a..13a6f4af8 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -55,58 +55,37 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: pip install -r requirements.txt -r requirements-dev.txt + - name: Install uv + uses: useblacksmith/setup-uv@v4 + with: + enable-cache: true - - name: Install Limbo - run: pip install -e . + - name: Install the project + run: uv sync --all-extras --dev - name: Run Pytest - run: pytest tests + run: uvx pytest tests lint: runs-on: blacksmith-4vcpu-ubuntu-2404 - defaults: - run: - working-directory: ${{ env.working-directory }} - steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Python uses: useblacksmith/setup-python@v6 + + - name: Install uv + uses: useblacksmith/setup-uv@v4 with: - python-version: "3.12" + enable-cache: true - - name: Install dev dependencies - run: pip install -r requirements-dev.txt + - name: Install the project + run: uv sync --all-extras --dev --all-packages - - name: Run lint - run: make lint - - check-requirements: - runs-on: blacksmith-4vcpu-ubuntu-2404 - - defaults: - run: - working-directory: ${{ env.working-directory }} - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Set up Python - uses: useblacksmith/setup-python@v6 - with: - python-version: "3.12" - - - name: Install pip-tools - run: pip install pip-tools - -# - name: Check requirements files -# run: make check-requirements + - name: Ruff lint + run: uvx ruff check linux: runs-on: blacksmith-4vcpu-ubuntu-2404 diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 4ed6066ce..91490121c 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -82,3 +82,17 @@ exclude_lines = [ 'if TYPE_CHECKING:', '@overload', ] + +[dependency-groups] +dev = [ + "coverage>=7.6.1", + "iniconfig>=2.1.0", + "maturin>=1.7.8", + "mypy>=1.11.0", + "mypy-extensions>=1.1.0", + "pluggy>=1.6.0", + "pytest>=8.3.1", + "pytest-cov>=5.0.0", + "ruff>=0.5.4", + "typing-extensions>=4.13.0", +] diff --git a/uv.lock b/uv.lock index d4b2db9d5..c0f209392 100644 --- a/uv.lock +++ b/uv.lock @@ -430,6 +430,20 @@ dev = [ { name = "ruff" }, ] +[package.dev-dependencies] +dev = [ + { name = "coverage" }, + { name = "iniconfig" }, + { name = "maturin" }, + { name = "mypy" }, + { name = "mypy-extensions" }, + { name = "pluggy" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "ruff" }, + { name = "typing-extensions" }, +] + [package.metadata] requires-dist = [ { name = "coverage", marker = "extra == 'dev'", specifier = "==7.6.1" }, @@ -442,6 +456,20 @@ requires-dist = [ ] provides-extras = ["dev"] +[package.metadata.requires-dev] +dev = [ + { name = "coverage", specifier = ">=7.6.1" }, + { name = "iniconfig", specifier = ">=2.1.0" }, + { name = "maturin", specifier = ">=1.7.8" }, + { name = "mypy", specifier = ">=1.11.0" }, + { name = "mypy-extensions", specifier = ">=1.1.0" }, + { name = "pluggy", specifier = ">=1.6.0" }, + { name = "pytest", specifier = ">=8.3.1" }, + { name = "pytest-cov", specifier = ">=5.0.0" }, + { name = "ruff", specifier = ">=0.5.4" }, + { name = "typing-extensions", specifier = ">=4.13.0" }, +] + [[package]] name = "pynacl" version = "1.5.0" From 50c8b2ca2edb2b3c8699d7ef515c9b917970b146 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 19 Jun 2025 16:51:00 -0300 Subject: [PATCH 3/5] extract ruff lint rules to workspace --- bindings/python/pyproject.toml | 13 ------------- pyproject.toml | 13 +++++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bindings/python/pyproject.toml b/bindings/python/pyproject.toml index 91490121c..4b6509391 100644 --- a/bindings/python/pyproject.toml +++ b/bindings/python/pyproject.toml @@ -53,19 +53,6 @@ strip-extras = true header = false upgrade = false -[tool.ruff] -line-length = 120 - -[tool.ruff.lint] -extend-select = [ - "E", # pycodestyle errors - "W", # pycodestyle warings - "F", # pyflakes - 'Q', # flake8-quotes - 'C90', # mccabe - 'I', # isort -] - [tool.pytest.ini_options] testpaths = 'tests' log_format = '%(name)s %(levelname)s: %(message)s' diff --git a/pyproject.toml b/pyproject.toml index 4e069035c..5878a7264 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,3 +15,16 @@ limbo_test = { workspace = true } [tool.uv.workspace] members = ["testing", "scripts", "antithesis-tests", "bindings/python"] + +[tool.ruff] +line-length = 120 + +[tool.ruff.lint] +extend-select = [ + "E", # pycodestyle errors + "W", # pycodestyle warings + "F", # pyflakes + 'Q', # flake8-quotes + 'C90', # mccabe + 'I', # isort +] From 80ccca8827d108ce05d65a8b280731d7732c4487 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 19 Jun 2025 16:59:49 -0300 Subject: [PATCH 4/5] ruff lint fix --- .../bank-test/anytime_validate.py | 19 ++--- .../bank-test/eventually_validate.py | 19 ++--- .../bank-test/finally_validate.py | 19 ++--- antithesis-tests/bank-test/first_setup.py | 24 +++---- .../parallel_driver_generate_transaction.py | 25 ++++--- .../stress-composer/first_setup.py | 55 +++++++------- .../stress-composer/parallel_driver_delete.py | 24 +++---- .../stress-composer/parallel_driver_insert.py | 29 ++++---- .../parallel_driver_integritycheck.py | 21 +++--- .../stress-composer/parallel_driver_update.py | 30 ++++---- antithesis-tests/stress-composer/utils.py | 19 ++--- bindings/python/tests/test_database.py | 3 +- perf/latency/limbo/gen-database.py | 16 +++-- perf/latency/limbo/plot.py | 51 +++++++------ perf/latency/rusqlite/gen-database.py | 16 +++-- perf/latency/rusqlite/plot.py | 39 +++++----- scripts/merge-pr.py | 60 +++++++++------- scripts/update-version.py | 72 ++++++++----------- testing/cli_tests/cli_test_cases.py | 71 ++++++------------ testing/cli_tests/collate.py | 8 +-- testing/cli_tests/console.py | 9 +-- testing/cli_tests/constraint.py | 25 +++---- testing/cli_tests/extensions.py | 46 ++++-------- testing/cli_tests/memory.py | 3 +- testing/cli_tests/test_limbo_cli.py | 15 ++-- testing/cli_tests/update.py | 18 ++--- testing/cli_tests/vfs_bench.py | 22 +++--- testing/cli_tests/write.py | 10 ++- testing/gen-database.py | 41 +++++++---- 29 files changed, 375 insertions(+), 434 deletions(-) diff --git a/antithesis-tests/bank-test/anytime_validate.py b/antithesis-tests/bank-test/anytime_validate.py index 28153613d..de3835003 100755 --- a/antithesis-tests/bank-test/anytime_validate.py +++ b/antithesis-tests/bank-test/anytime_validate.py @@ -1,7 +1,6 @@ #!/usr/bin/env -S python3 -u import limbo -from antithesis.random import get_random from antithesis.assertions import always try: @@ -12,20 +11,16 @@ except Exception as e: cur = con.cursor() -initial_state = cur.execute(f''' +initial_state = cur.execute(""" SELECT * FROM initial_state -''').fetchone() +""").fetchone() -curr_total = cur.execute(f''' +curr_total = cur.execute(""" SELECT SUM(balance) AS total FROM accounts; -''').fetchone() +""").fetchone() always( - initial_state[1] == curr_total[0], - '[Anytime] Initial balance always equals current balance', - { - 'init_bal': initial_state[1], - 'curr_bal': curr_total[0] - } + initial_state[1] == curr_total[0], + "[Anytime] Initial balance always equals current balance", + {"init_bal": initial_state[1], "curr_bal": curr_total[0]}, ) - diff --git a/antithesis-tests/bank-test/eventually_validate.py b/antithesis-tests/bank-test/eventually_validate.py index dde671bdd..21a6c9a81 100755 --- a/antithesis-tests/bank-test/eventually_validate.py +++ b/antithesis-tests/bank-test/eventually_validate.py @@ -1,7 +1,6 @@ #!/usr/bin/env -S python3 -u import limbo -from antithesis.random import get_random from antithesis.assertions import always try: @@ -12,20 +11,16 @@ except Exception as e: cur = con.cursor() -initial_state = cur.execute(f''' +initial_state = cur.execute(""" SELECT * FROM initial_state -''').fetchone() +""").fetchone() -curr_total = cur.execute(f''' +curr_total = cur.execute(""" SELECT SUM(balance) AS total FROM accounts; -''').fetchone() +""").fetchone() always( - initial_state[1] == curr_total[0], - '[Eventually] Initial balance always equals current balance', - { - 'init_bal': initial_state[1], - 'curr_bal': curr_total[0] - } + initial_state[1] == curr_total[0], + "[Eventually] Initial balance always equals current balance", + {"init_bal": initial_state[1], "curr_bal": curr_total[0]}, ) - diff --git a/antithesis-tests/bank-test/finally_validate.py b/antithesis-tests/bank-test/finally_validate.py index 79ef6e385..1d9cc0e7b 100755 --- a/antithesis-tests/bank-test/finally_validate.py +++ b/antithesis-tests/bank-test/finally_validate.py @@ -1,7 +1,6 @@ #!/usr/bin/env -S python3 -u import limbo -from antithesis.random import get_random from antithesis.assertions import always try: @@ -12,20 +11,16 @@ except Exception as e: cur = con.cursor() -initial_state = cur.execute(f''' +initial_state = cur.execute(""" SELECT * FROM initial_state -''').fetchone() +""").fetchone() -curr_total = cur.execute(f''' +curr_total = cur.execute(""" SELECT SUM(balance) AS total FROM accounts; -''').fetchone() +""").fetchone() always( - initial_state[1] == curr_total[0], - '[Finally] Initial balance always equals current balance', - { - 'init_bal': initial_state[1], - 'curr_bal': curr_total[0] - } + initial_state[1] == curr_total[0], + "[Finally] Initial balance always equals current balance", + {"init_bal": initial_state[1], "curr_bal": curr_total[0]}, ) - diff --git a/antithesis-tests/bank-test/first_setup.py b/antithesis-tests/bank-test/first_setup.py index fac764cb1..b99791d7e 100755 --- a/antithesis-tests/bank-test/first_setup.py +++ b/antithesis-tests/bank-test/first_setup.py @@ -12,16 +12,16 @@ except Exception as e: cur = con.cursor() # drop accounts table if it exists and create a new table -cur.execute(f''' +cur.execute(""" DROP TABLE IF EXISTS accounts; -''') +""") -cur.execute(f''' +cur.execute(""" CREATE TABLE accounts ( account_id INTEGER PRIMARY KEY AUTOINCREMENT, balance REAL NOT NULL DEFAULT 0.0 ); -''') +""") # randomly create up to 100 accounts with a balance up to 1e9 total = 0 @@ -29,24 +29,24 @@ num_accts = get_random() % 100 + 1 for i in range(num_accts): bal = get_random() % 1e9 total += bal - cur.execute(f''' + cur.execute(f""" INSERT INTO accounts (balance) VALUES ({bal}) - ''') + """) # drop initial_state table if it exists and create a new table -cur.execute(f''' +cur.execute(""" DROP TABLE IF EXISTS initial_state; -''') -cur.execute(f''' +""") +cur.execute(""" CREATE TABLE initial_state ( num_accts INTEGER, total REAL ); -''') +""") # store initial state in the table -cur.execute(f''' +cur.execute(f""" INSERT INTO initial_state (num_accts, total) VALUES ({num_accts}, {total}) -''') \ No newline at end of file +""") diff --git a/antithesis-tests/bank-test/parallel_driver_generate_transaction.py b/antithesis-tests/bank-test/parallel_driver_generate_transaction.py index 6e22a3b64..6378dc855 100755 --- a/antithesis-tests/bank-test/parallel_driver_generate_transaction.py +++ b/antithesis-tests/bank-test/parallel_driver_generate_transaction.py @@ -1,14 +1,17 @@ #!/usr/bin/env -S python3 -u -import limbo import logging from logging.handlers import RotatingFileHandler + +import limbo from antithesis.random import get_random -handler = RotatingFileHandler(filename='bank_test.log', mode='a', maxBytes=1*1024*1024, backupCount=5, encoding=None, delay=0) +handler = RotatingFileHandler( + filename="bank_test.log", mode="a", maxBytes=1 * 1024 * 1024, backupCount=5, encoding=None, delay=0 +) handler.setLevel(logging.INFO) -logger = logging.getLogger('root') +logger = logging.getLogger("root") logger.setLevel(logging.INFO) logger.addHandler(handler) @@ -23,6 +26,7 @@ cur = con.cursor() length = cur.execute("SELECT num_accts FROM initial_state").fetchone()[0] + def transaction(): # check that sender and recipient are different sender = get_random() % length + 1 @@ -34,23 +38,24 @@ def transaction(): logger.info(f"Sender ID: {sender} | Recipient ID: {recipient} | Txn Val: {value}") cur.execute("BEGIN TRANSACTION;") - + # subtract value from balance of the sender account - cur.execute(f''' - UPDATE accounts + cur.execute(f""" + UPDATE accounts SET balance = balance - {value} WHERE account_id = {sender}; - ''') + """) # add value to balance of the recipient account - cur.execute(f''' - UPDATE accounts + cur.execute(f""" + UPDATE accounts SET balance = balance + {value} WHERE account_id = {recipient}; - ''') + """) cur.execute("COMMIT;") + # run up to 100 transactions iterations = get_random() % 100 # logger.info(f"Starting {iterations} iterations") diff --git a/antithesis-tests/stress-composer/first_setup.py b/antithesis-tests/stress-composer/first_setup.py index 68fb9e368..84a18f73a 100755 --- a/antithesis-tests/stress-composer/first_setup.py +++ b/antithesis-tests/stress-composer/first_setup.py @@ -1,22 +1,23 @@ #!/usr/bin/env -S python3 -u -import json import glob +import json import os + import limbo from antithesis.random import get_random, random_choice -constraints = ['NOT NULL', ''] -data_type = ['INTEGER', 'REAL', 'TEXT', 'BLOB', 'NUMERIC'] +constraints = ["NOT NULL", ""] +data_type = ["INTEGER", "REAL", "TEXT", "BLOB", "NUMERIC"] # remove any existing db files -for f in glob.glob('*.db'): +for f in glob.glob("*.db"): try: os.remove(f) except OSError: pass -for f in glob.glob('*.db-wal'): +for f in glob.glob("*.db-wal"): try: os.remove(f) except OSError: @@ -24,17 +25,17 @@ for f in glob.glob('*.db-wal'): # store initial states in a separate db try: - con_init = limbo.connect('init_state.db') + con_init = limbo.connect("init_state.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) cur_init = con_init.cursor() -cur_init.execute('CREATE TABLE schemas (schema TEXT, tbl INT)') -cur_init.execute('CREATE TABLE tables (count INT)') +cur_init.execute("CREATE TABLE schemas (schema TEXT, tbl INT)") +cur_init.execute("CREATE TABLE tables (count INT)") try: - con = limbo.connect('stress_composer.db') + con = limbo.connect("stress_composer.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) @@ -43,43 +44,43 @@ cur = con.cursor() tbl_count = max(1, get_random() % 10) -cur_init.execute(f'INSERT INTO tables (count) VALUES ({tbl_count})') +cur_init.execute(f"INSERT INTO tables (count) VALUES ({tbl_count})") schemas = [] for i in range(tbl_count): col_count = max(1, get_random() % 10) pk = get_random() % col_count - schema = { - 'table': i, - 'colCount': col_count, - 'pk': pk - } + schema = {"table": i, "colCount": col_count, "pk": pk} cols = [] - cols_str = '' + cols_str = "" for j in range(col_count): col_data_type = random_choice(data_type) col_constraint_1 = random_choice(constraints) col_constraint_2 = random_choice(constraints) - col = f'col_{j} {col_data_type} {col_constraint_1} {col_constraint_2 if col_constraint_2 != col_constraint_1 else ""}' if j != pk else f'col_{j} {col_data_type}' + col = ( + f"col_{j} {col_data_type} {col_constraint_1} {col_constraint_2 if col_constraint_2 != col_constraint_1 else ''}" # noqa: E501 + if j != pk + else f"col_{j} {col_data_type}" + ) cols.append(col) - schema[f'col_{j}'] = { - 'data_type': col_data_type, - 'constraint1': col_constraint_1 if j != pk else '', - 'constraint2': col_constraint_2 if col_constraint_1 != col_constraint_2 else "" if j != pk else 'NOT NULL', + schema[f"col_{j}"] = { + "data_type": col_data_type, + "constraint1": col_constraint_1 if j != pk else "", + "constraint2": col_constraint_2 if col_constraint_1 != col_constraint_2 else "" if j != pk else "NOT NULL", } - cols_str = ', '.join(cols) - - schemas.append(schema) + cols_str = ", ".join(cols) + + schemas.append(schema) cur_init.execute(f"INSERT INTO schemas (schema, tbl) VALUES ('{json.dumps(schema)}', {i})") - cur.execute(f''' + cur.execute(f""" CREATE TABLE tbl_{i} ({cols_str}) - ''') + """) -print(f'DB Schemas\n------------\n{json.dumps(schemas, indent=2)}') \ No newline at end of file +print(f"DB Schemas\n------------\n{json.dumps(schemas, indent=2)}") diff --git a/antithesis-tests/stress-composer/parallel_driver_delete.py b/antithesis-tests/stress-composer/parallel_driver_delete.py index 222922411..47857c4e2 100755 --- a/antithesis-tests/stress-composer/parallel_driver_delete.py +++ b/antithesis-tests/stress-composer/parallel_driver_delete.py @@ -1,42 +1,42 @@ #!/usr/bin/env -S python3 -u import json + import limbo -from utils import generate_random_value from antithesis.random import get_random +from utils import generate_random_value # Get initial state try: - con_init = limbo.connect('init_state.db') + con_init = limbo.connect("init_state.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) cur_init = con_init.cursor() -tbl_len = cur_init.execute('SELECT count FROM tables').fetchone()[0] +tbl_len = cur_init.execute("SELECT count FROM tables").fetchone()[0] selected_tbl = get_random() % tbl_len -tbl_schema = json.loads(cur_init.execute(f'SELECT schema FROM schemas WHERE tbl = {selected_tbl}').fetchone()[0]) +tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl = {selected_tbl}").fetchone()[0]) # get primary key column -pk = tbl_schema['pk'] +pk = tbl_schema["pk"] # get non-pk columns -cols = [f'col_{col}' for col in range(tbl_schema['colCount']) if col != pk] +cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk] try: - con = limbo.connect('stress_composer.db') + con = limbo.connect("stress_composer.db") except limbo.OperationalError as e: - print(f'Failed to open stress_composer.db. Exiting... {e}') + print(f"Failed to open stress_composer.db. Exiting... {e}") exit(0) cur = con.cursor() deletions = get_random() % 100 -print(f'Attempt to delete {deletions} rows in tbl_{selected_tbl}...') +print(f"Attempt to delete {deletions} rows in tbl_{selected_tbl}...") for i in range(deletions): where_clause = f"col_{pk} = {generate_random_value(tbl_schema[f'col_{pk}']['data_type'])}" - cur.execute(f''' + cur.execute(f""" DELETE FROM tbl_{selected_tbl} WHERE {where_clause} - ''') - + """) diff --git a/antithesis-tests/stress-composer/parallel_driver_insert.py b/antithesis-tests/stress-composer/parallel_driver_insert.py index b0bb16db2..e1d273eb8 100755 --- a/antithesis-tests/stress-composer/parallel_driver_insert.py +++ b/antithesis-tests/stress-composer/parallel_driver_insert.py @@ -1,44 +1,44 @@ #!/usr/bin/env -S python3 -u import json -import limbo -from utils import generate_random_value -from antithesis.random import get_random +import limbo +from antithesis.random import get_random +from utils import generate_random_value # Get initial state try: - con_init = limbo.connect('init_state.db') + con_init = limbo.connect("init_state.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) cur_init = con_init.cursor() -tbl_len = cur_init.execute('SELECT count FROM tables').fetchone()[0] +tbl_len = cur_init.execute("SELECT count FROM tables").fetchone()[0] selected_tbl = get_random() % tbl_len -tbl_schema = json.loads(cur_init.execute(f'SELECT schema FROM schemas WHERE tbl = {selected_tbl}').fetchone()[0]) -cols = ', '.join([f'col_{col}' for col in range(tbl_schema['colCount'])]) +tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl = {selected_tbl}").fetchone()[0]) +cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])]) try: - con = limbo.connect('stress_composer.db') + con = limbo.connect("stress_composer.db") except limbo.OperationalError as e: - print(f'Failed to open stress_composer.db. Exiting... {e}') + print(f"Failed to open stress_composer.db. Exiting... {e}") exit(0) cur = con.cursor() # insert up to 100 rows in the selected table insertions = get_random() % 100 -print(f'Inserting {insertions} rows...') +print(f"Inserting {insertions} rows...") for i in range(insertions): - values = [generate_random_value(tbl_schema[f'col_{col}']['data_type']) for col in range(tbl_schema['colCount'])] + values = [generate_random_value(tbl_schema[f"col_{col}"]["data_type"]) for col in range(tbl_schema["colCount"])] try: - cur.execute(f''' + cur.execute(f""" INSERT INTO tbl_{selected_tbl} ({cols}) - VALUES ({', '.join(values)}) - ''') + VALUES ({", ".join(values)}) + """) except limbo.OperationalError as e: if "UNIQUE constraint failed" in str(e): # Ignore UNIQUE constraint violations @@ -46,4 +46,3 @@ for i in range(insertions): else: # Re-raise other operational errors raise - diff --git a/antithesis-tests/stress-composer/parallel_driver_integritycheck.py b/antithesis-tests/stress-composer/parallel_driver_integritycheck.py index 277392e4c..62fcc49ac 100755 --- a/antithesis-tests/stress-composer/parallel_driver_integritycheck.py +++ b/antithesis-tests/stress-composer/parallel_driver_integritycheck.py @@ -1,33 +1,34 @@ #!/usr/bin/env -S python3 -u import json + import limbo -from antithesis.random import get_random from antithesis.assertions import always +from antithesis.random import get_random # Get initial state try: - con_init = limbo.connect('init_state.db') + con_init = limbo.connect("init_state.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) cur_init = con_init.cursor() -tbl_len = cur_init.execute('SELECT count FROM tables').fetchone()[0] +tbl_len = cur_init.execute("SELECT count FROM tables").fetchone()[0] selected_tbl = get_random() % tbl_len -tbl_schema = json.loads(cur_init.execute(f'SELECT schema FROM schemas WHERE tbl = {selected_tbl}').fetchone()[0]) -cols = ', '.join([f'col_{col}' for col in range(tbl_schema['colCount'])]) +tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl = {selected_tbl}").fetchone()[0]) +cols = ", ".join([f"col_{col}" for col in range(tbl_schema["colCount"])]) try: - con = limbo.connect('stress_composer.db') + con = limbo.connect("stress_composer.db") except limbo.OperationalError as e: - print(f'Failed to open stress_composer.db. Exiting... {e}') + print(f"Failed to open stress_composer.db. Exiting... {e}") exit(0) -cur = con.cursor(); +cur = con.cursor() -print('Running integrity check...') +print("Running integrity check...") result = cur.execute("PRAGMA integrity_check") row = result.fetchone() -always(row == ("ok",), f"Integrity check failed: {row}", {}) \ No newline at end of file +always(row == ("ok",), f"Integrity check failed: {row}", {}) diff --git a/antithesis-tests/stress-composer/parallel_driver_update.py b/antithesis-tests/stress-composer/parallel_driver_update.py index 1be30b98d..14a02efde 100755 --- a/antithesis-tests/stress-composer/parallel_driver_update.py +++ b/antithesis-tests/stress-composer/parallel_driver_update.py @@ -1,57 +1,58 @@ #!/usr/bin/env -S python3 -u import json + import limbo -from utils import generate_random_value from antithesis.random import get_random +from utils import generate_random_value # Get initial state try: - con_init = limbo.connect('init_state.db') + con_init = limbo.connect("init_state.db") except Exception as e: print(f"Error connecting to database: {e}") exit(0) cur_init = con_init.cursor() -tbl_len = cur_init.execute('SELECT count FROM tables').fetchone()[0] +tbl_len = cur_init.execute("SELECT count FROM tables").fetchone()[0] selected_tbl = get_random() % tbl_len -tbl_schema = json.loads(cur_init.execute(f'SELECT schema FROM schemas WHERE tbl = {selected_tbl}').fetchone()[0]) +tbl_schema = json.loads(cur_init.execute(f"SELECT schema FROM schemas WHERE tbl = {selected_tbl}").fetchone()[0]) # get primary key column -pk = tbl_schema['pk'] +pk = tbl_schema["pk"] # get non-pk columns -cols = [f'col_{col}' for col in range(tbl_schema['colCount']) if col != pk] +cols = [f"col_{col}" for col in range(tbl_schema["colCount"]) if col != pk] # print(cols) try: - con = limbo.connect('stress_composer.db') + con = limbo.connect("stress_composer.db") except limbo.OperationalError as e: - print(f'Failed to open stress_composer.db. Exiting... {e}') + print(f"Failed to open stress_composer.db. Exiting... {e}") exit(0) cur = con.cursor() # insert up to 100 rows in the selected table updates = get_random() % 100 -print(f'Attempt to update {updates} rows in tbl_{selected_tbl}...') +print(f"Attempt to update {updates} rows in tbl_{selected_tbl}...") for i in range(updates): - set_clause = '' - if tbl_schema['colCount'] == 1: + set_clause = "" + if tbl_schema["colCount"] == 1: set_clause = f"col_{pk} = {generate_random_value(tbl_schema[f'col_{pk}']['data_type'])}" else: values = [] for col in cols: # print(col) values.append(f"{col} = {generate_random_value(tbl_schema[col]['data_type'])}") - set_clause = ', '.join(values) + set_clause = ", ".join(values) where_clause = f"col_{pk} = {generate_random_value(tbl_schema[f'col_{pk}']['data_type'])}" # print(where_clause) try: - cur.execute(f''' + cur.execute(f""" UPDATE tbl_{selected_tbl} SET {set_clause} WHERE {where_clause} - ''') + """) except limbo.OperationalError as e: if "UNIQUE constraint failed" in str(e): # Ignore UNIQUE constraint violations @@ -59,4 +60,3 @@ for i in range(updates): else: # Re-raise other operational errors raise - diff --git a/antithesis-tests/stress-composer/utils.py b/antithesis-tests/stress-composer/utils.py index 358e44670..dc0fd7ab1 100755 --- a/antithesis-tests/stress-composer/utils.py +++ b/antithesis-tests/stress-composer/utils.py @@ -1,19 +1,22 @@ import string + from antithesis.random import get_random, random_choice + def generate_random_identifier(type: str, num: int): - return ''.join(type, '_', get_random() % num) + return "".join(type, "_", get_random() % num) + def generate_random_value(type_str): - if type_str == 'INTEGER': + if type_str == "INTEGER": return str(get_random() % 100) - elif type_str == 'REAL': - return '{:.2f}'.format(get_random() % 100 / 100.0) - elif type_str == 'TEXT': + elif type_str == "REAL": + return "{:.2f}".format(get_random() % 100 / 100.0) + elif type_str == "TEXT": return f"'{''.join(random_choice(string.ascii_lowercase) for _ in range(5))}'" - elif type_str == 'BLOB': + elif type_str == "BLOB": return f"x'{''.join(random_choice(string.ascii_lowercase) for _ in range(5)).encode().hex()}'" - elif type_str == 'NUMERIC': + elif type_str == "NUMERIC": return str(get_random() % 100) else: - return NULL + return "NULL" diff --git a/bindings/python/tests/test_database.py b/bindings/python/tests/test_database.py index 9ef047e19..07e8508cc 100644 --- a/bindings/python/tests/test_database.py +++ b/bindings/python/tests/test_database.py @@ -1,9 +1,8 @@ import os import sqlite3 -import pytest - import limbo +import pytest @pytest.fixture(autouse=True) diff --git a/perf/latency/limbo/gen-database.py b/perf/latency/limbo/gen-database.py index e5e9157b8..ef61a5626 100755 --- a/perf/latency/limbo/gen-database.py +++ b/perf/latency/limbo/gen-database.py @@ -2,11 +2,12 @@ import argparse import sqlite3 + from faker import Faker parser = argparse.ArgumentParser() -parser.add_argument('filename') -parser.add_argument('-c', '--count', type=int) +parser.add_argument("filename") +parser.add_argument("-c", "--count", type=int) args = parser.parse_args() @@ -14,7 +15,7 @@ conn = sqlite3.connect(args.filename) cursor = conn.cursor() # Create the user table -cursor.execute(''' +cursor.execute(""" CREATE TABLE IF NOT EXISTS user ( id INTEGER PRIMARY KEY, first_name TEXT, @@ -26,7 +27,7 @@ cursor.execute(''' state TEXT, zipcode TEXT ) -''') +""") fake = Faker() for _ in range(args.count): @@ -39,10 +40,13 @@ for _ in range(args.count): state = fake.state_abbr() zipcode = fake.zipcode() - cursor.execute(''' + cursor.execute( + """ INSERT INTO user (first_name, last_name, email, phone_number, address, city, state, zipcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ''', (first_name, last_name, email, phone_number, address, city, state, zipcode)) + """, + (first_name, last_name, email, phone_number, address, city, state, zipcode), + ) conn.commit() conn.close() diff --git a/perf/latency/limbo/plot.py b/perf/latency/limbo/plot.py index 584e062f8..ef88c7c08 100755 --- a/perf/latency/limbo/plot.py +++ b/perf/latency/limbo/plot.py @@ -1,16 +1,15 @@ #!/usr/bin/env python3 -import matplotlib.pyplot as plt -import matplotlib import csv -font = {'family' : 'normal', - 'weight' : 'bold', - 'size' : 22} +import matplotlib +import matplotlib.pyplot as plt -matplotlib.rcParams.update({'font.size': 22}) +font = {"family": "normal", "weight": "bold", "size": 22} -file_name = 'results.csv' +matplotlib.rcParams.update({"font.size": 22}) + +file_name = "results.csv" threads = [] p50_values = [] p95_values = [] @@ -22,34 +21,34 @@ p99_limbo = [] p999_limbo = [] # Parse the CSV file -with open(file_name, 'r') as csvfile: +with open(file_name, "r") as csvfile: reader = csv.DictReader(csvfile) for row in reader: - if row['system'] == 'rusqlite': - threads.append(int(row['count'])) - p50_values.append(float(row['p50']) / 1e3) - p95_values.append(float(row['p95']) / 1e3) - p99_values.append(float(row['p99']) / 1e3) - p999_values.append(float(row['p999']) / 1e3) + if row["system"] == "rusqlite": + threads.append(int(row["count"])) + p50_values.append(float(row["p50"]) / 1e3) + p95_values.append(float(row["p95"]) / 1e3) + p99_values.append(float(row["p99"]) / 1e3) + p999_values.append(float(row["p999"]) / 1e3) else: - p95_limbo.append(float(row['p95']) / 1e3) - p99_limbo.append(float(row['p99']) / 1e3) - p999_limbo.append(float(row['p999']) / 1e3) + p95_limbo.append(float(row["p95"]) / 1e3) + p99_limbo.append(float(row["p99"]) / 1e3) + p999_limbo.append(float(row["p999"]) / 1e3) plt.figure(figsize=(10, 6)) -plt.plot(threads, p999_values, label='rusqlite (p999)', linestyle='solid', marker='$\u2217$') -plt.plot(threads, p999_limbo, label='limbo (p999)', linestyle='solid', marker='$\u2217$') -plt.plot(threads, p99_values, label='rusqlite (p99)', linestyle='solid', marker='$\u002B$') -plt.plot(threads, p99_limbo, label='limbo (p99)', linestyle='solid', marker='$\u002B$') -#plt.plot(threads, p95_values, label='p95', linestyle='solid', marker="$\u25FE$") -#plt.plot(threads, p50_values, label='p50', linestyle='solid', marker="$\u25B2$") +plt.plot(threads, p999_values, label="rusqlite (p999)", linestyle="solid", marker="$\u2217$") +plt.plot(threads, p999_limbo, label="limbo (p999)", linestyle="solid", marker="$\u2217$") +plt.plot(threads, p99_values, label="rusqlite (p99)", linestyle="solid", marker="$\u002b$") +plt.plot(threads, p99_limbo, label="limbo (p99)", linestyle="solid", marker="$\u002b$") +# plt.plot(threads, p95_values, label='p95', linestyle='solid', marker="$\u25FE$") +# plt.plot(threads, p50_values, label='p50', linestyle='solid', marker="$\u25B2$") plt.yscale("log") -plt.xlabel('Number of Tenants') -plt.ylabel('Latency (µs)') +plt.xlabel("Number of Tenants") +plt.ylabel("Latency (µs)") plt.grid(True) plt.legend() plt.tight_layout() -plt.savefig('latency_distribution.pdf') +plt.savefig("latency_distribution.pdf") diff --git a/perf/latency/rusqlite/gen-database.py b/perf/latency/rusqlite/gen-database.py index e5e9157b8..ef61a5626 100755 --- a/perf/latency/rusqlite/gen-database.py +++ b/perf/latency/rusqlite/gen-database.py @@ -2,11 +2,12 @@ import argparse import sqlite3 + from faker import Faker parser = argparse.ArgumentParser() -parser.add_argument('filename') -parser.add_argument('-c', '--count', type=int) +parser.add_argument("filename") +parser.add_argument("-c", "--count", type=int) args = parser.parse_args() @@ -14,7 +15,7 @@ conn = sqlite3.connect(args.filename) cursor = conn.cursor() # Create the user table -cursor.execute(''' +cursor.execute(""" CREATE TABLE IF NOT EXISTS user ( id INTEGER PRIMARY KEY, first_name TEXT, @@ -26,7 +27,7 @@ cursor.execute(''' state TEXT, zipcode TEXT ) -''') +""") fake = Faker() for _ in range(args.count): @@ -39,10 +40,13 @@ for _ in range(args.count): state = fake.state_abbr() zipcode = fake.zipcode() - cursor.execute(''' + cursor.execute( + """ INSERT INTO user (first_name, last_name, email, phone_number, address, city, state, zipcode) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - ''', (first_name, last_name, email, phone_number, address, city, state, zipcode)) + """, + (first_name, last_name, email, phone_number, address, city, state, zipcode), + ) conn.commit() conn.close() diff --git a/perf/latency/rusqlite/plot.py b/perf/latency/rusqlite/plot.py index a39118511..dd01c9657 100755 --- a/perf/latency/rusqlite/plot.py +++ b/perf/latency/rusqlite/plot.py @@ -1,16 +1,15 @@ #!/usr/bin/env python3 -import matplotlib.pyplot as plt -import matplotlib import csv -font = {'family' : 'normal', - 'weight' : 'bold', - 'size' : 22} +import matplotlib +import matplotlib.pyplot as plt -matplotlib.rcParams.update({'font.size': 22}) +font = {"family": "normal", "weight": "bold", "size": 22} -file_name = 'results.csv' +matplotlib.rcParams.update({"font.size": 22}) + +file_name = "results.csv" threads = [] p50_values = [] p95_values = [] @@ -18,27 +17,27 @@ p99_values = [] p999_values = [] # Parse the CSV file -with open(file_name, 'r') as csvfile: +with open(file_name, "r") as csvfile: reader = csv.DictReader(csvfile) for row in reader: - threads.append(int(row['count'])) - p50_values.append(float(row['p50']) / 1e3) - p95_values.append(float(row['p95']) / 1e3) - p99_values.append(float(row['p99']) / 1e3) - p999_values.append(float(row['p999']) / 1e3) + threads.append(int(row["count"])) + p50_values.append(float(row["p50"]) / 1e3) + p95_values.append(float(row["p95"]) / 1e3) + p99_values.append(float(row["p99"]) / 1e3) + p999_values.append(float(row["p999"]) / 1e3) plt.figure(figsize=(10, 6)) -plt.plot(threads, p999_values, label='p999', linestyle='solid', marker='$\u2217$') -plt.plot(threads, p99_values, label='p99', linestyle='solid', marker='$\u002B$') -plt.plot(threads, p95_values, label='p95', linestyle='solid', marker="$\u25FE$") -plt.plot(threads, p50_values, label='p50', linestyle='solid', marker="$\u25B2$") +plt.plot(threads, p999_values, label="p999", linestyle="solid", marker="$\u2217$") +plt.plot(threads, p99_values, label="p99", linestyle="solid", marker="$\u002b$") +plt.plot(threads, p95_values, label="p95", linestyle="solid", marker="$\u25fe$") +plt.plot(threads, p50_values, label="p50", linestyle="solid", marker="$\u25b2$") plt.yscale("log") -plt.xlabel('Number of Threads') -plt.ylabel('Latency (µs)') +plt.xlabel("Number of Threads") +plt.ylabel("Latency (µs)") plt.grid(True) plt.legend() plt.tight_layout() -plt.savefig('latency_distribution.pdf') +plt.savefig("latency_distribution.pdf") diff --git a/scripts/merge-pr.py b/scripts/merge-pr.py index a6188b466..de3feadd2 100755 --- a/scripts/merge-pr.py +++ b/scripts/merge-pr.py @@ -9,29 +9,33 @@ # ``` # pip install PyGithub # ``` -import sys -import re -from github import Github +import json import os +import re import subprocess +import sys import tempfile import textwrap -import json + +from github import Github + def run_command(command): - process = subprocess.Popen( - command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) output, error = process.communicate() - return output.decode('utf-8').strip(), error.decode('utf-8').strip(), process.returncode + return output.decode("utf-8").strip(), error.decode("utf-8").strip(), process.returncode -def load_user_mapping(file_path='.github.json'): + +def load_user_mapping(file_path=".github.json"): if os.path.exists(file_path): - with open(file_path, 'r') as f: + with open(file_path, "r") as f: return json.load(f) return {} + user_mapping = load_user_mapping() + def get_user_email(g, username): if username in user_mapping: return f"{user_mapping[username]['name']} <{user_mapping[username]['email']}>" @@ -48,6 +52,7 @@ def get_user_email(g, username): # If we couldn't find an email, return a noreply address return f"{username} <{username}@users.noreply.github.com>" + def get_pr_info(g, repo, pr_number): pr = repo.get_pull(int(pr_number)) author = pr.user @@ -57,41 +62,43 @@ def get_pr_info(g, repo, pr_number): reviewed_by = [] reviews = pr.get_reviews() for review in reviews: - if review.state == 'APPROVED': + if review.state == "APPROVED": reviewer = review.user reviewed_by.append(get_user_email(g, reviewer.login)) return { - 'number': pr.number, - 'title': pr.title, - 'author': author_name, - 'head': pr.head.ref, - 'head_sha': pr.head.sha, - 'body': pr.body.strip() if pr.body else '', - 'reviewed_by': reviewed_by + "number": pr.number, + "title": pr.title, + "author": author_name, + "head": pr.head.ref, + "head_sha": pr.head.sha, + "body": pr.body.strip() if pr.body else "", + "reviewed_by": reviewed_by, } + def wrap_text(text, width=72): - lines = text.split('\n') + lines = text.split("\n") wrapped_lines = [] in_code_block = False for line in lines: - if line.strip().startswith('```'): + if line.strip().startswith("```"): in_code_block = not in_code_block wrapped_lines.append(line) elif in_code_block: wrapped_lines.append(line) else: wrapped_lines.extend(textwrap.wrap(line, width=width)) - return '\n'.join(wrapped_lines) + return "\n".join(wrapped_lines) + def merge_pr(pr_number): # GitHub authentication - token = os.getenv('GITHUB_TOKEN') + token = os.getenv("GITHUB_TOKEN") g = Github(token) # Get the repository - repo_name = os.getenv('GITHUB_REPOSITORY') + repo_name = os.getenv("GITHUB_REPOSITORY") if not repo_name: print("Error: GITHUB_REPOSITORY environment variable not set") sys.exit(1) @@ -102,19 +109,19 @@ def merge_pr(pr_number): # Format commit message commit_title = f"Merge '{pr_info['title']}' from {pr_info['author']}" - commit_body = wrap_text(pr_info['body']) + commit_body = wrap_text(pr_info["body"]) commit_message = f"{commit_title}\n\n{commit_body}\n" # Add Reviewed-by lines - for approver in pr_info['reviewed_by']: + for approver in pr_info["reviewed_by"]: commit_message += f"\nReviewed-by: {approver}" # Add Closes line commit_message += f"\n\nCloses #{pr_info['number']}" # Create a temporary file for the commit message - with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_file: + with tempfile.NamedTemporaryFile(mode="w", delete=False) as temp_file: temp_file.write(commit_message) temp_file_path = temp_file.name @@ -147,13 +154,14 @@ def merge_pr(pr_number): # Clean up the temporary file os.unlink(temp_file_path) + if __name__ == "__main__": if len(sys.argv) != 2: print("Usage: python merge_pr.py ") sys.exit(1) pr_number = sys.argv[1] - if not re.match(r'^\d+$', pr_number): + if not re.match(r"^\d+$", pr_number): print("Error: PR number must be a positive integer") sys.exit(1) diff --git a/scripts/update-version.py b/scripts/update-version.py index 6a54d0196..92c139b50 100755 --- a/scripts/update-version.py +++ b/scripts/update-version.py @@ -6,22 +6,21 @@ updates the JavaScript and WebAssembly bindings package.json and package-lock.js uses cargo update to update Cargo.lock, creates a git commit, and adds a version tag. """ -import re import argparse -import sys import json -import subprocess import os +import re +import subprocess +import sys from pathlib import Path - # Define all npm package paths in one place NPM_PACKAGES = [ "bindings/javascript", "bindings/javascript/npm/darwin-universal", - "bindings/javascript/npm/linux-x64-gnu", + "bindings/javascript/npm/linux-x64-gnu", "bindings/javascript/npm/win32-x64-msvc", - "bindings/wasm" + "bindings/wasm", ] @@ -29,10 +28,7 @@ def parse_args(): parser = argparse.ArgumentParser(description="Update version in project files") # Version argument - parser.add_argument( - "version", - help="The new version to set (e.g., 0.1.0)" - ) + parser.add_argument("version", help="The new version to set (e.g., 0.1.0)") return parser.parse_args() @@ -58,7 +54,7 @@ def update_cargo_toml(new_version): # Pattern to match version in various contexts while maintaining the quotes pattern = r'(version\s*=\s*)"' + re.escape(current_version) + r'"' - updated_content = re.sub(pattern, fr'\1"{new_version}"', content) + updated_content = re.sub(pattern, rf'\1"{new_version}"', content) cargo_path.write_text(updated_content) return True @@ -66,7 +62,7 @@ def update_cargo_toml(new_version): sys.exit(1) -def update_package_json(dir_path, new_version): +def update_package_json(dir_path, new_version): # noqa: C901 """Update version in package.json and package-lock.json files.""" dir_path = Path(dir_path) @@ -77,14 +73,14 @@ def update_package_json(dir_path, new_version): return False # Read and parse the package.json file - with open(package_path, 'r') as f: + with open(package_path, "r") as f: package_data = json.load(f) # Update version regardless of current value - package_data['version'] = new_version + package_data["version"] = new_version # Write updated package.json - with open(package_path, 'w') as f: + with open(package_path, "w") as f: json.dump(package_data, f, indent=2) except Exception: return False @@ -96,27 +92,27 @@ def update_package_json(dir_path, new_version): return True # package.json was updated successfully # Read and parse the package-lock.json file - with open(lock_path, 'r') as f: + with open(lock_path, "r") as f: lock_data = json.load(f) # Update version in multiple places in package-lock.json - if 'version' in lock_data: - lock_data['version'] = new_version + if "version" in lock_data: + lock_data["version"] = new_version # Update version in packages section if it exists (npm >= 7) - if 'packages' in lock_data: - if '' in lock_data['packages']: # Root package - if 'version' in lock_data['packages']['']: - lock_data['packages']['']['version'] = new_version + if "packages" in lock_data: + if "" in lock_data["packages"]: # Root package + if "version" in lock_data["packages"][""]: + lock_data["packages"][""]["version"] = new_version # Update version in dependencies section if it exists (older npm) - package_name = package_data.get('name', '') - if 'dependencies' in lock_data and package_name in lock_data['dependencies']: - if 'version' in lock_data['dependencies'][package_name]: - lock_data['dependencies'][package_name]['version'] = new_version + package_name = package_data.get("name", "") + if "dependencies" in lock_data and package_name in lock_data["dependencies"]: + if "version" in lock_data["dependencies"][package_name]: + lock_data["dependencies"][package_name]["version"] = new_version # Write updated package-lock.json - with open(lock_path, 'w') as f: + with open(lock_path, "w") as f: json.dump(lock_data, f, indent=2) return True @@ -137,10 +133,7 @@ def run_cargo_update(): """Run cargo update to update the Cargo.lock file.""" try: # Run cargo update showing its output with verbose flag - subprocess.run( - ["cargo", "update", "--workspace", "--verbose"], - check=True - ) + subprocess.run(["cargo", "update", "--workspace", "--verbose"], check=True) return True except Exception: return False @@ -156,7 +149,7 @@ def create_git_commit_and_tag(version): for package_path in NPM_PACKAGES: package_json = f"{package_path}/package.json" package_lock = f"{package_path}/package-lock.json" - + if os.path.exists(package_json): files_to_add.append(package_json) if os.path.exists(package_lock): @@ -165,26 +158,17 @@ def create_git_commit_and_tag(version): # Add each file individually for file in files_to_add: try: - subprocess.run( - ["git", "add", file], - check=True - ) + subprocess.run(["git", "add", file], check=True) except subprocess.CalledProcessError: print(f"Warning: Could not add {file} to git") # Create commit commit_message = f"Limbo {version}" - subprocess.run( - ["git", "commit", "-m", commit_message], - check=True - ) + subprocess.run(["git", "commit", "-m", commit_message], check=True) # Create tag tag_name = f"v{version}" - subprocess.run( - ["git", "tag", "-a", tag_name, "-m", f"Version {version}"], - check=True - ) + subprocess.run(["git", "tag", "-a", tag_name, "-m", f"Version {version}"], check=True) return True except Exception as e: diff --git a/testing/cli_tests/cli_test_cases.py b/testing/cli_tests/cli_test_cases.py index ba5e9a38f..9e2aac1fb 100755 --- a/testing/cli_tests/cli_test_cases.py +++ b/testing/cli_tests/cli_test_cases.py @@ -1,9 +1,10 @@ #!/usr/bin/env python3 -from cli_tests.test_limbo_cli import TestLimboShell -from pathlib import Path -import time import os +import time +from pathlib import Path + from cli_tests import console +from cli_tests.test_limbo_cli import TestLimboShell def test_basic_queries(): @@ -62,7 +63,7 @@ def test_joins(): shell.run_test( "file-cross-join", "select * from users, products limit 1;", - "1|Jamie|Foster|dylan00@example.com|496-522-9493|62375 Johnson Rest Suite 322|West Lauriestad|IL|35865|94|1|hat|79.0", + "1|Jamie|Foster|dylan00@example.com|496-522-9493|62375 Johnson Rest Suite 322|West Lauriestad|IL|35865|94|1|hat|79.0", # noqa: E501 ) shell.quit() @@ -76,7 +77,7 @@ def test_left_join_self(): shell.run_test( "file-left-join-self", - "select u1.first_name as user_name, u2.first_name as neighbor_name from users u1 left join users as u2 on u1.id = u2.id + 1 limit 2;", + "select u1.first_name as user_name, u2.first_name as neighbor_name from users u1 left join users as u2 on u1.id = u2.id + 1 limit 2;", # noqa: E501 "Jamie|\nCindy|Jamie", ) shell.quit() @@ -99,9 +100,7 @@ def test_switch_back_to_in_memory(): shell.run_test("open-testing-db-file", ".open testing/testing.db", "") # Then switch back to :memory: shell.run_test("switch-back", ".open :memory:", "") - shell.run_test( - "schema-in-memory", ".schema users", "-- Error: Table 'users' not found." - ) + shell.run_test("schema-in-memory", ".schema users", "-- Error: Table 'users' not found.") shell.quit() @@ -172,9 +171,7 @@ SELECT 2;""" def test_comments(): shell = TestLimboShell() shell.run_test("single-line-comment", "-- this is a comment\nSELECT 1;", "1") - shell.run_test( - "multi-line-comments", "-- First comment\n-- Second comment\nSELECT 2;", "2" - ) + shell.run_test("multi-line-comments", "-- First comment\n-- Second comment\nSELECT 2;", "2") shell.run_test("block-comment", "/*\nMulti-line block comment\n*/\nSELECT 3;", "3") shell.run_test( "inline-comments", @@ -187,9 +184,7 @@ def test_comments(): def test_import_csv(): shell = TestLimboShell() shell.run_test("memory-db", ".open :memory:", "") - shell.run_test( - "create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "" - ) + shell.run_test("create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "") shell.run_test( "import-csv-no-options", ".import --csv ./testing/test_files/test.csv csv_table", @@ -206,9 +201,7 @@ def test_import_csv(): def test_import_csv_verbose(): shell = TestLimboShell() shell.run_test("open-memory", ".open :memory:", "") - shell.run_test( - "create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "" - ) + shell.run_test("create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "") shell.run_test( "import-csv-verbose", ".import --csv -v ./testing/test_files/test.csv csv_table", @@ -225,9 +218,7 @@ def test_import_csv_verbose(): def test_import_csv_skip(): shell = TestLimboShell() shell.run_test("open-memory", ".open :memory:", "") - shell.run_test( - "create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "" - ) + shell.run_test("create-csv-table", "CREATE TABLE csv_table (c1 INT, c2 REAL, c3 String);", "") shell.run_test( "import-csv-skip", ".import --csv --skip 1 ./testing/test_files/test.csv csv_table", @@ -250,51 +241,33 @@ def test_update_with_limit(): limbo.run_test("update-limit", "UPDATE t SET a = 10 LIMIT 1;", "") limbo.run_test("update-limit-result", "SELECT COUNT(*) from t WHERE a = 10;", "1") limbo.run_test("update-limit-zero", "UPDATE t SET a = 100 LIMIT 0;", "") - limbo.run_test( - "update-limit-zero-result", "SELECT COUNT(*) from t WHERE a = 100;", "0" - ) + limbo.run_test("update-limit-zero-result", "SELECT COUNT(*) from t WHERE a = 100;", "0") limbo.run_test("update-limit-all", "UPDATE t SET a = 100 LIMIT -1;", "") # negative limit is treated as no limit in sqlite due to check for --val = 0 limbo.run_test("update-limit-result", "SELECT COUNT(*) from t WHERE a = 100;", "6") - limbo.run_test( - "udpate-limit-where", "UPDATE t SET a = 333 WHERE b = 5 LIMIT 1;", "" - ) - limbo.run_test( - "update-limit-where-result", "SELECT COUNT(*) from t WHERE a = 333;", "1" - ) + limbo.run_test("udpate-limit-where", "UPDATE t SET a = 333 WHERE b = 5 LIMIT 1;", "") + limbo.run_test("update-limit-where-result", "SELECT COUNT(*) from t WHERE a = 333;", "1") limbo.quit() - def test_update_with_limit_and_offset(): limbo = TestLimboShell( "CREATE TABLE t (a,b,c); insert into t values (1,2,3), (4,5,6), (7,8,9), (1,2,3),(4,5,6), (7,8,9);" ) limbo.run_test("update-limit-offset", "UPDATE t SET a = 10 LIMIT 1 OFFSET 3;", "") - limbo.run_test( - "update-limit-offset-result", "SELECT COUNT(*) from t WHERE a = 10;", "1" - ) + limbo.run_test("update-limit-offset-result", "SELECT COUNT(*) from t WHERE a = 10;", "1") limbo.run_test("update-limit-result", "SELECT a from t LIMIT 4;", "1\n4\n7\n10") - limbo.run_test( - "update-limit-offset-zero", "UPDATE t SET a = 100 LIMIT 0 OFFSET 0;", "" - ) - limbo.run_test( - "update-limit-zero-result", "SELECT COUNT(*) from t WHERE a = 100;", "0" - ) + limbo.run_test("update-limit-offset-zero", "UPDATE t SET a = 100 LIMIT 0 OFFSET 0;", "") + limbo.run_test("update-limit-zero-result", "SELECT COUNT(*) from t WHERE a = 100;", "0") limbo.run_test("update-limit-all", "UPDATE t SET a = 100 LIMIT -1 OFFSET 1;", "") limbo.run_test("update-limit-result", "SELECT COUNT(*) from t WHERE a = 100;", "5") - limbo.run_test( - "udpate-limit-where", "UPDATE t SET a = 333 WHERE b = 5 LIMIT 1 OFFSET 2;", "" - ) - limbo.run_test( - "update-limit-where-result", "SELECT COUNT(*) from t WHERE a = 333;", "0" - ) + limbo.run_test("udpate-limit-where", "UPDATE t SET a = 333 WHERE b = 5 LIMIT 1 OFFSET 2;", "") + limbo.run_test("update-limit-where-result", "SELECT COUNT(*) from t WHERE a = 333;", "0") limbo.quit() - + + def test_insert_default_values(): - limbo = TestLimboShell( - "CREATE TABLE t (a integer default(42),b integer default (43),c integer default(44));" - ) + limbo = TestLimboShell("CREATE TABLE t (a integer default(42),b integer default (43),c integer default(44));") for _ in range(1, 10): limbo.execute_dot("INSERT INTO t DEFAULT VALUES;") limbo.run_test("insert-default-values", "SELECT * FROM t;", "42|43|44\n" * 9) diff --git a/testing/cli_tests/collate.py b/testing/cli_tests/collate.py index 8a88d8943..02a2d10d8 100644 --- a/testing/cli_tests/collate.py +++ b/testing/cli_tests/collate.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 import os + +from cli_tests import console from cli_tests.test_limbo_cli import TestLimboShell from pydantic import BaseModel -from cli_tests import console - sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") @@ -81,13 +81,13 @@ class CollateTest(BaseModel): ) limbo.run_test( - "Grouping is performed using the NOCASE collating sequence (Values 'abc', 'ABC', and 'Abc' are placed in the same group).", + "Grouping is performed using the NOCASE collating sequence (Values 'abc', 'ABC', and 'Abc' are placed in the same group).", # noqa: E501 "SELECT count(*) FROM t1 GROUP BY d ORDER BY 1;", "\n".join(map(lambda x: str(x), [4])), ) limbo.run_test( - "Grouping is performed using the BINARY collating sequence. 'abc' and 'ABC' and 'Abc' form different groups", + "Grouping is performed using the BINARY collating sequence. 'abc' and 'ABC' and 'Abc' form different groups", # noqa: E501 "SELECT count(*) FROM t1 GROUP BY (d || '') ORDER BY 1;", "\n".join(map(lambda x: str(x), [1, 1, 2])), ) diff --git a/testing/cli_tests/console.py b/testing/cli_tests/console.py index 2f295a90d..19e489cab 100644 --- a/testing/cli_tests/console.py +++ b/testing/cli_tests/console.py @@ -1,8 +1,8 @@ from typing import Any, Optional, Union -from rich.console import Console, JustifyMethod -from rich.theme import Theme -from rich.style import Style +from rich.console import Console, JustifyMethod +from rich.style import Style +from rich.theme import Theme custom_theme = Theme( { @@ -95,6 +95,7 @@ def debug( _stack_offset=_stack_offset + 1, ) + def test( *objects: Any, sep: str = " ", @@ -119,4 +120,4 @@ def test( highlight=highlight, log_locals=log_locals, _stack_offset=_stack_offset + 1, - ) \ No newline at end of file + ) diff --git a/testing/cli_tests/constraint.py b/testing/cli_tests/constraint.py index 3ea61ce9b..6d18bf819 100644 --- a/testing/cli_tests/constraint.py +++ b/testing/cli_tests/constraint.py @@ -2,15 +2,16 @@ # Eventually extract these tests to be in the fuzzing integration tests import os -import tempfile -from faker import Faker -from faker.providers.lorem.en_US import Provider as P -from cli_tests.test_limbo_cli import TestLimboShell -from pydantic import BaseModel -from cli_tests import console -from enum import Enum import random import sqlite3 +import tempfile +from enum import Enum + +from cli_tests import console +from cli_tests.test_limbo_cli import TestLimboShell +from faker import Faker +from faker.providers.lorem.en_US import Provider as P +from pydantic import BaseModel sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") @@ -233,11 +234,7 @@ class Table(BaseModel): # These statements should always cause a constraint error as there is no where clause here def generate_update(self) -> str: - vals = [ - f"{col.name} = {col.col_type.generate(fake)}" - for col in self.columns - if col.primary_key - ] + vals = [f"{col.name} = {col.col_type.generate(fake)}" for col in self.columns if col.primary_key] vals = ", ".join(vals) return f"UPDATE {self.name} SET {vals};" @@ -374,7 +371,7 @@ def main(): tests = all_tests() for test in tests: console.info(test.table) - with tempfile.NamedTemporaryFile(suffix='.db') as tmp: + with tempfile.NamedTemporaryFile(suffix=".db") as tmp: try: # Use with syntax to automatically close shell on error with TestLimboShell("") as limbo: @@ -387,7 +384,7 @@ def main(): tests = [custom_test_2, regression_test_update_single_key] for test in tests: - with tempfile.NamedTemporaryFile(suffix='.db') as tmp: + with tempfile.NamedTemporaryFile(suffix=".db") as tmp: try: with TestLimboShell("") as limbo: limbo.execute_dot(f".open {tmp.name}") diff --git a/testing/cli_tests/extensions.py b/testing/cli_tests/extensions.py index f996942d3..3a603cbb7 100755 --- a/testing/cli_tests/extensions.py +++ b/testing/cli_tests/extensions.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 import os -from cli_tests.test_limbo_cli import TestLimboShell + from cli_tests import console +from cli_tests.test_limbo_cli import TestLimboShell sqlite_exec = "./scripts/limbo-sqlite3" sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") @@ -40,14 +41,10 @@ def test_uuid(): ) limbo.run_test_fn("SELECT uuid4_str();", lambda res: len(res) == 36) limbo.run_test_fn("SELECT hex(uuid7());", lambda res: int(res, 16) is not None) - limbo.run_test_fn( - "SELECT uuid7_timestamp_ms(uuid7()) / 1000;", lambda res: res.isdigit() - ) + limbo.run_test_fn("SELECT uuid7_timestamp_ms(uuid7()) / 1000;", lambda res: res.isdigit()) limbo.run_test_fn("SELECT uuid7_str();", validate_string_uuid) limbo.run_test_fn("SELECT uuid_str(uuid7());", validate_string_uuid) - limbo.run_test_fn( - "SELECT hex(uuid_blob(uuid7_str()));", lambda res: int(res, 16) is not None - ) + limbo.run_test_fn("SELECT hex(uuid_blob(uuid7_str()));", lambda res: int(res, 16) is not None) limbo.run_test_fn("SELECT uuid_str(uuid_blob(uuid7_str()));", validate_string_uuid) limbo.run_test_fn( f"SELECT uuid7_timestamp_ms('{specific_time}') / 1000;", @@ -160,12 +157,8 @@ def test_aggregates(): validate_percentile2, "test aggregate percentile function with 1 argument works", ) - limbo.run_test_fn( - "SELECT percentile_cont(value, 0.25) from test;", validate_percentile1 - ) - limbo.run_test_fn( - "SELECT percentile_disc(value, 0.55) from test;", validate_percentile_disc - ) + limbo.run_test_fn("SELECT percentile_cont(value, 0.25) from test;", validate_percentile1) + limbo.run_test_fn("SELECT percentile_disc(value, 0.55) from test;", validate_percentile_disc) limbo.quit() @@ -223,8 +216,7 @@ def test_crypto(): # Hashing and Decode limbo.run_test_fn( "SELECT crypto_encode(crypto_blake3('abc'), 'hex');", - lambda res: res - == "6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85", + lambda res: res == "6437b3ac38465133ffb63b75273a8db548c558465d79db03fd359c6cd5bd9d85", "blake3 should encrypt correctly", ) limbo.run_test_fn( @@ -239,8 +231,7 @@ def test_crypto(): ) limbo.run_test_fn( "SELECT crypto_encode(crypto_sha256('abc'), 'hex');", - lambda a: a - == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + lambda a: a == "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "sha256 should encrypt correctly", ) limbo.run_test_fn( @@ -252,7 +243,7 @@ def test_crypto(): limbo.run_test_fn( "SELECT crypto_encode(crypto_sha512('abc'), 'hex');", lambda a: a - == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + == "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", # noqa: E501 "sha512 should encrypt correctly", ) @@ -401,9 +392,7 @@ def test_kv(): ) for i in range(100): limbo.execute_dot(f"insert into t values ('key{i}', 'val{i}');") - limbo.run_test_fn( - "select count(*) from t;", lambda res: "100" == res, "can insert 100 rows" - ) + limbo.run_test_fn("select count(*) from t;", lambda res: "100" == res, "can insert 100 rows") limbo.run_test_fn("update t set value = 'updated' where key = 'key33';", null) limbo.run_test_fn( "select * from t where key = 'key33';", @@ -422,12 +411,8 @@ def test_kv(): "can update all rows", ) limbo.run_test_fn("delete from t limit 96;", null, "can delete 96 rows") - limbo.run_test_fn( - "select count(*) from t;", lambda res: "4" == res, "four rows remain" - ) - limbo.run_test_fn( - "update t set key = '100' where 1;", null, "where clause evaluates properly" - ) + limbo.run_test_fn("select count(*) from t;", lambda res: "4" == res, "four rows remain") + limbo.run_test_fn("update t set key = '100' where 1;", null, "where clause evaluates properly") limbo.run_test_fn( "select * from t where key = '100';", lambda res: res == "100|updated2", @@ -509,9 +494,7 @@ def test_vfs(): ext_path = "target/debug/liblimbo_ext_tests" limbo.run_test_fn(".vfslist", lambda x: "testvfs" not in x, "testvfs not loaded") limbo.execute_dot(f".load {ext_path}") - limbo.run_test_fn( - ".vfslist", lambda res: "testvfs" in res, "testvfs extension loaded" - ) + limbo.run_test_fn(".vfslist", lambda res: "testvfs" in res, "testvfs extension loaded") limbo.execute_dot(".open testing/vfs.db testvfs") limbo.execute_dot("create table test (id integer primary key, value float);") limbo.execute_dot("create table vfs (id integer primary key, value blob);") @@ -742,8 +725,7 @@ def test_tablestats(): limbo.run_test_fn( "SELECT * FROM stats ORDER BY name;", - lambda res: sorted(_split(res)) - == sorted(["logs|1", "people|3", "products|11", "users|10000"]), + lambda res: sorted(_split(res)) == sorted(["logs|1", "people|3", "products|11", "users|10000"]), "stats shows correct initial counts (and skips itself)", ) diff --git a/testing/cli_tests/memory.py b/testing/cli_tests/memory.py index 474fcae7d..da4f7b458 100755 --- a/testing/cli_tests/memory.py +++ b/testing/cli_tests/memory.py @@ -1,7 +1,8 @@ #!/usr/bin/env python3 import os -from cli_tests.test_limbo_cli import TestLimboShell + from cli_tests import console +from cli_tests.test_limbo_cli import TestLimboShell sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") diff --git a/testing/cli_tests/test_limbo_cli.py b/testing/cli_tests/test_limbo_cli.py index 2e0f21ad3..b29d69f1e 100755 --- a/testing/cli_tests/test_limbo_cli.py +++ b/testing/cli_tests/test_limbo_cli.py @@ -1,12 +1,12 @@ #!/usr/bin/env python3 import os import select -from time import sleep import subprocess from pathlib import Path +from time import sleep from typing import Callable, List, Optional -from cli_tests import console +from cli_tests import console PIPE_BUF = 4096 @@ -107,7 +107,7 @@ class TestLimboShell: flags="", ): if exec_name is None: - exec_name = os.environ.get('SQLITE_EXEC') + exec_name = os.environ.get("SQLITE_EXEC") if exec_name is None: exec_name = "./scripts/limbo-sqlite3" if flags == "": @@ -142,10 +142,7 @@ INSERT INTO t VALUES (zeroblob(1024 - 1), zeroblob(1024 - 2), zeroblob(1024 - 3) console.test(f"Running test: {name}", _stack_offset=2) actual = self.shell.execute(sql) assert actual == expected, ( - f"Test failed: {name}\n" - f"SQL: {sql}\n" - f"Expected:\n{repr(expected)}\n" - f"Actual:\n{repr(actual)}" + f"Test failed: {name}\nSQL: {sql}\nExpected:\n{repr(expected)}\nActual:\n{repr(actual)}" ) def run_debug(self, sql: str): @@ -153,9 +150,7 @@ INSERT INTO t VALUES (zeroblob(1024 - 1), zeroblob(1024 - 2), zeroblob(1024 - 3) actual = self.shell.execute(sql) console.debug(f"OUTPUT:\n{repr(actual)}", _stack_offset=2) - def run_test_fn( - self, sql: str, validate: Callable[[str], bool], desc: str = "" - ) -> None: + def run_test_fn(self, sql: str, validate: Callable[[str], bool], desc: str = "") -> None: # Print the test that is executing before executing the sql command # Printing later confuses the user of the code what test has actually failed if desc: diff --git a/testing/cli_tests/update.py b/testing/cli_tests/update.py index 1d0d23b63..09c71440a 100644 --- a/testing/cli_tests/update.py +++ b/testing/cli_tests/update.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 import os + +from cli_tests import console from cli_tests.test_limbo_cli import TestLimboShell from pydantic import BaseModel -from cli_tests import console - sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") @@ -39,10 +39,7 @@ class UpdateTest(BaseModel): f"{self.vals}", ) - stmt = [ - f"SELECT hex(t1), t2, t3 FROM test LIMIT 1 OFFSET {i};" - for i in range(self.vals) - ] + stmt = [f"SELECT hex(t1), t2, t3 FROM test LIMIT 1 OFFSET {i};" for i in range(self.vals)] expected = [f"{zero_blob}|{t2_val}|{t3_val}" for _ in range(self.vals)] sqlite.run_test( @@ -84,15 +81,10 @@ class UpdateTest(BaseModel): f"{self.vals}", ) - stmt = [ - f"SELECT hex(t1), t2, t3 FROM test LIMIT 1 OFFSET {i};" - for i in range(self.vals) - ] + stmt = [f"SELECT hex(t1), t2, t3 FROM test LIMIT 1 OFFSET {i};" for i in range(self.vals)] expected = [ - f"{zero_blob}|{t2_val}|{t3_val}" - if i != 0 - else f"{zero_blob}|{t2_update_val}|{t3_val}" + f"{zero_blob}|{t2_val}|{t3_val}" if i != 0 else f"{zero_blob}|{t2_update_val}|{t3_val}" for i in range(self.vals) ] sqlite.run_test( diff --git a/testing/cli_tests/vfs_bench.py b/testing/cli_tests/vfs_bench.py index ae5a969d0..712bd147b 100644 --- a/testing/cli_tests/vfs_bench.py +++ b/testing/cli_tests/vfs_bench.py @@ -1,16 +1,16 @@ #!/usr/bin/env python3 # vfs benchmarking/comparison -import os -from pathlib import Path -import subprocess -import statistics import argparse +import os +import statistics +import subprocess +from pathlib import Path from time import perf_counter, sleep from typing import Dict +from cli_tests.console import error, info, test from cli_tests.test_limbo_cli import TestLimboShell -from cli_tests.console import info, error, test LIMBO_BIN = Path("./target/release/limbo") DB_FILE = Path("testing/temp.db") @@ -37,9 +37,7 @@ def bench_one(vfs: str, sql: str, iterations: int) -> list[float]: for i in range(1, iterations + 1): start = perf_counter() - _ = shell.run_test_fn( - sql, lambda x: x is not None and append_time(times, start, perf_counter) - ) + _ = shell.run_test_fn(sql, lambda x: x is not None and append_time(times, start, perf_counter)) test(f" {vfs} | run {i:>3}: {times[-1]:.6f}s") shell.quit() @@ -60,9 +58,7 @@ def cleanup_temp_db() -> None: def main() -> None: - parser = argparse.ArgumentParser( - description="Benchmark a SQL statement against all Limbo VFS back‑ends." - ) + parser = argparse.ArgumentParser(description="Benchmark a SQL statement against all Limbo VFS back‑ends.") parser.add_argument("sql", help="SQL statement to execute (quote it)") parser.add_argument("iterations", type=int, help="number of repetitions") args = parser.parse_args() @@ -105,9 +101,7 @@ def main() -> None: else: pct = (avg - baseline_avg) / baseline_avg * 100.0 faster_slower = "slower" if pct > 0 else "faster" - info( - f"{vfs:<{name_pad}} : {avg:.6f} ({abs(pct):.1f}% {faster_slower} than {baseline})" - ) + info(f"{vfs:<{name_pad}} : {avg:.6f} ({abs(pct):.1f}% {faster_slower} than {baseline})") info("-" * 60) cleanup_temp_db() diff --git a/testing/cli_tests/write.py b/testing/cli_tests/write.py index 8c0d91943..d661e7076 100755 --- a/testing/cli_tests/write.py +++ b/testing/cli_tests/write.py @@ -1,11 +1,11 @@ #!/usr/bin/env python3 import os import tempfile -from cli_tests.test_limbo_cli import TestLimboShell -from pydantic import BaseModel -from cli_tests import console from time import sleep +from cli_tests import console +from cli_tests.test_limbo_cli import TestLimboShell +from pydantic import BaseModel sqlite_flags = os.getenv("SQLITE_FLAGS", "-q").split(" ") @@ -46,9 +46,7 @@ class InsertTest(BaseModel): big_stmt = "".join(big_stmt) expected = "\n".join(expected) - limbo.run_test_fn( - big_stmt, lambda res: validate_with_expected(res, expected), self.name - ) + limbo.run_test_fn(big_stmt, lambda res: validate_with_expected(res, expected), self.name) def test_compat(self): console.info("Testing in SQLite\n") diff --git a/testing/gen-database.py b/testing/gen-database.py index 47108dfd2..bc8b9c9a9 100755 --- a/testing/gen-database.py +++ b/testing/gen-database.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 import sqlite3 + from faker import Faker -conn = sqlite3.connect('database.db') +conn = sqlite3.connect("database.db") cursor = conn.cursor() # Create the user table -cursor.execute(''' +cursor.execute(""" CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, first_name TEXT, @@ -20,18 +21,29 @@ cursor.execute(''' zipcode TEXT, age INTEGER ) -''') +""") -cursor.execute(''' +cursor.execute(""" CREATE TABLE IF NOT EXISTS products ( id INTEGER PRIMARY KEY, name TEXT, price REAL ) -''') +""") -product_list = ["hat", "cap", "shirt", "sweater", "sweatshirt", - "shorts", "jeans", "sneakers", "boots", "coat", "accessories"] +product_list = [ + "hat", + "cap", + "shirt", + "sweater", + "sweatshirt", + "shorts", + "jeans", + "sneakers", + "boots", + "coat", + "accessories", +] fake = Faker() for _ in range(10000): @@ -45,18 +57,23 @@ for _ in range(10000): zipcode = fake.zipcode() age = fake.random_int(min=1, max=100) - cursor.execute(''' + cursor.execute( + """ INSERT INTO users (first_name, last_name, email, phone_number, address, city, state, zipcode, age) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) - ''', (first_name, last_name, email, phone_number, address, city, state, zipcode, age)) + """, + (first_name, last_name, email, phone_number, address, city, state, zipcode, age), + ) for product in product_list: price = fake.random_int(min=1, max=100) - cursor.execute(''' + cursor.execute( + """ INSERT INTO products (name, price) VALUES (?, ?) - ''', (product, price)) - + """, + (product, price), + ) conn.commit() From 8b8f43334e85fd1e7d3e77efd296be78ad805241 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Thu, 19 Jun 2025 17:00:51 -0300 Subject: [PATCH 5/5] remove python makefile as it is obsolete with UV --- bindings/python/Makefile | 37 ------------------------------------- 1 file changed, 37 deletions(-) delete mode 100644 bindings/python/Makefile diff --git a/bindings/python/Makefile b/bindings/python/Makefile deleted file mode 100644 index f685fa651..000000000 --- a/bindings/python/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -REQUIREMENTS := requirements.txt -REQUIREMENTS_DEV := requirements-dev.txt - -all: check-requirements install lint test -.PHONY: all - -install: - @echo "Installing requirements..." - pip install -r requirements.txt -r requirements-dev.txt -.PHONY: install - -test: - @echo "Running tests..." - pytest -.PHONY: test - -lint: - @echo "Running linters..." - ruff check - ruff format --diff -.PHONY: lint - -check-requirements: - @echo "Checking requirements files..." - mkdir -p .tmp - pip-compile pyproject.toml --quiet --output-file=.tmp/$(REQUIREMENTS) - pip-compile pyproject.toml --quiet --extra=dev --output-file=.tmp/$(REQUIREMENTS_DEV) - diff -u $(REQUIREMENTS) .tmp/$(REQUIREMENTS) || (echo "$(REQUIREMENTS) doesn't match pyproject.toml" && exit 1) - diff -u $(REQUIREMENTS_DEV) .tmp/$(REQUIREMENTS_DEV) || (echo "$(REQUIREMENTS_DEV) doesn't match pyproject.toml" && exit 1) - @echo "Requirements files match pyproject.toml" -.PHONY: check-requirements - -compile-requirements: - @echo "Compiling requirements files..." - pip-compile pyproject.toml --output-file=$(REQUIREMENTS) - pip-compile pyproject.toml --extra=dev --output-file=$(REQUIREMENTS_DEV) -.PHONY: compile-requirements