diff --git a/README.md b/README.md index 6c00e56..532be82 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ # `rules_pycross` - Python + cross platform -Use your Poetry or PDM lock files with Bazel and enabling cross-platform builds. +Use your Poetry or PDM or UV lock files with Bazel and enabling cross-platform builds. ### Features: -- A single lock file for all target platforms, thanks to Poetry and PDM +- A single lock file for all target platforms, thanks to Poetry, PDM and UV - Builds that happen in build actions, not during WORKSPACE initialization - Standard Bazel `http_file` rules used for fetching dependencies. `pip` is not a build-time dependency. +> **Notice:** UV is still experimental + See the [examples](examples). ### Why? diff --git a/docs/ext_lock_import.md b/docs/ext_lock_import.md index e41e259..a96bcb3 100644 --- a/docs/ext_lock_import.md +++ b/docs/ext_lock_import.md @@ -14,6 +14,10 @@ lock_import.import_pdm( require_static_urls, target_environments) lock_import.import_poetry(default_alias_single_version, disallow_builds, local_wheels, lock_file, project_file, repo, target_environments) +lock_import.import_uv(all_development_groups, all_optional_groups, default, + default_alias_single_version, development_groups, disallow_builds, local_wheels, + lock_file, optional_groups, project_file, repo, require_static_urls, + target_environments) lock_import.package(name, always_build, build_dependencies, build_target, ignore_dependencies, install_exclude_globs, repo) @@ -38,7 +42,7 @@ Import a PDM lock file. | development_groups | List of development dependency groups to install. | List of strings | optional | `[]` | | disallow_builds | If True, only pre-built wheels are allowed. | Boolean | optional | `False` | | local_wheels | A list of local .whl files to consider when processing lock files. | List of labels | optional | `[]` | -| lock_file | The pdm.lock file. | Label | required | | +| lock_file | The lock file. | Label | required | | | optional_groups | List of optional dependency groups to install. | List of strings | optional | `[]` | | project_file | The pyproject.toml file. | Label | required | | | repo | The repository name | String | required | | @@ -63,6 +67,30 @@ Import a Poetry lock file. | repo | The repository name | String | required | | | target_environments | A list of target environment descriptors. | List of labels | optional | `["@pycross_environments//:environments"]` | + + +### import_uv + +Import a uv lock file. + +**Attributes** + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| all_development_groups | Install all dev dependencies. | Boolean | optional | `False` | +| all_optional_groups | Install all optional dependencies. | Boolean | optional | `False` | +| default | Whether to install dependencies from the default group. | Boolean | optional | `True` | +| default_alias_single_version | Generate aliases for all packages that have a single version in the lock file. | Boolean | optional | `False` | +| development_groups | List of development dependency groups to install. | List of strings | optional | `[]` | +| disallow_builds | If True, only pre-built wheels are allowed. | Boolean | optional | `False` | +| local_wheels | A list of local .whl files to consider when processing lock files. | List of labels | optional | `[]` | +| lock_file | The lock file. | Label | required | | +| optional_groups | List of optional dependency groups to install. | List of strings | optional | `[]` | +| project_file | The pyproject.toml file. | Label | required | | +| repo | The repository name | String | required | | +| require_static_urls | Require that the lock file is created with --static-urls. | Boolean | optional | `True` | +| target_environments | A list of target environment descriptors. | List of labels | optional | `["@pycross_environments//:environments"]` | + ### package diff --git a/docs/rules.md b/docs/rules.md index b0b3da8..b8c6307 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -58,7 +58,7 @@ pycross_pdm_lock_model(name, all_optional_groups | Install all optional dependencies. | Boolean | optional | `False` | | default | Whether to install dependencies from the default group. | Boolean | optional | `True` | | development_groups | List of development dependency groups to install. | List of strings | optional | `[]` | -| lock_file | The pdm.lock file. | Label | required | | +| lock_file | The lock file. | Label | required | | | optional_groups | List of optional dependency groups to install. | List of strings | optional | `[]` | | project_file | The pyproject.toml file. | Label | required | | | require_static_urls | Require that the lock file is created with --static-urls. | Boolean | optional | `True` | diff --git a/docs/workspace_rules.md b/docs/workspace_rules.md index 1e20e38..393f57c 100644 --- a/docs/workspace_rules.md +++ b/docs/workspace_rules.md @@ -47,6 +47,32 @@ lock_repo_model_poetry(project_fi | lock_file |

-

| none | + + +## lock_repo_model_uv + +
+lock_repo_model_uv(project_file, lock_file, default, optional_groups, all_optional_groups,
+                   development_groups, all_development_groups, require_static_urls)
+
+ + + +**PARAMETERS** + + +| Name | Description | Default Value | +| :------------- | :------------- | :------------- | +| project_file |

-

| none | +| lock_file |

-

| none | +| default |

-

| `True` | +| optional_groups |

-

| `[]` | +| all_optional_groups |

-

| `False` | +| development_groups |

-

| `[]` | +| all_development_groups |

-

| `False` | +| require_static_urls |

-

| `True` | + + ## pycross_lock_repo diff --git a/e2e/bzlmod/MODULE.bazel b/e2e/bzlmod/MODULE.bazel index 4ec0308..eca4c16 100644 --- a/e2e/bzlmod/MODULE.bazel +++ b/e2e/bzlmod/MODULE.bazel @@ -89,6 +89,20 @@ lock_import.import_pdm( repo = "pdm", target_environments = ["@smoke_environments//:environments"], ) + +# lock_repo with UV and some package overrides +lock_import.import_uv( + default_alias_single_version = True, + local_wheels = [ + "//:cowsay-6.1-py3-none-any.whl", + ], + lock_file = "//:uv.lock", + project_file = "//:pyproject.toml", + repo = "uv", + target_environments = ["@smoke_environments//:environments"], +) + +# lock_repo with PDM and some package overrides lock_import.package( name = "regex", always_build = True, @@ -107,7 +121,7 @@ lock_import.package( # The actual repos are loaded from the lock_repos extension. lock_repos = use_extension("@rules_pycross//pycross/extensions:lock_repos.bzl", "lock_repos") -use_repo(lock_repos, "pdm", "poetry") +use_repo(lock_repos, "pdm", "poetry", "uv") # Lock repos for vended lock files lock_file = use_extension("@rules_pycross//pycross/extensions:lock_file.bzl", "lock_file") diff --git a/e2e/bzlmod/uv.lock b/e2e/bzlmod/uv.lock new file mode 100644 index 0000000..7c7dc1c --- /dev/null +++ b/e2e/bzlmod/uv.lock @@ -0,0 +1,477 @@ +version = 1 +requires-python = ">=3.9, <3.13" + +[[distribution]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321 }, +] + +[[distribution]] +name = "asttokens" +version = "2.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/1d/f03bcb60c4a3212e15f99a56085d93093a497718adf828d050b9d675da81/asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0", size = 62284 } +dependencies = [ + { name = "six" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/86/4736ac618d82a20d87d2f92ae19441ebc7ac9e7a581d7e58bbe79233b24a/asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", size = 27764 }, +] + +[[distribution]] +name = "cffi" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/68/ce/95b0bae7968c65473e1298efb042e10cafc7bafc14d9e4f154008241c91d/cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0", size = 512873 } +dependencies = [ + { name = "pycparser" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/aa/1c43e48a6f361d1529f9e4602d6992659a0107b5f21cae567e2eddcf8d66/cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088", size = 182457 }, + { url = "https://files.pythonhosted.org/packages/c4/01/f5116266fe80c04d4d1cc96c3d355606943f9fb604a810e0b02228a0ce19/cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9", size = 176792 }, + { url = "https://files.pythonhosted.org/packages/57/3a/c263cf4d5b02880274866968fa2bf196a02c4486248bc164732319b4a4c0/cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673", size = 423848 }, + { url = "https://files.pythonhosted.org/packages/f0/31/a6503a5c4874fb4d4c2053f73f09a957cb427b6943fab5a43b8e156df397/cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896", size = 446005 }, + { url = "https://files.pythonhosted.org/packages/22/05/43cfda378da7bb0aa19b3cf34fe54f8867b0d581294216339d87deefd69c/cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684", size = 452639 }, + { url = "https://files.pythonhosted.org/packages/54/49/b8875986beef2e74fc668b95f2df010e354f78e009d33d95b375912810c3/cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7", size = 434140 }, + { url = "https://files.pythonhosted.org/packages/c9/7c/43d81bdd5a915923c3bad5bb4bff401ea00ccc8e28433fb6083d2e3bf58e/cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614", size = 443865 }, + { url = "https://files.pythonhosted.org/packages/eb/de/4f644fc78a1144a897e1f908abfb2058f7be05a8e8e4fe90b7f41e9de36b/cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743", size = 436867 }, + { url = "https://files.pythonhosted.org/packages/ee/68/74a2b9f9432b70d97d1184cdabf32d7803124c228adef9481d280864a4a7/cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d", size = 465830 }, + { url = "https://files.pythonhosted.org/packages/20/18/76e26bcfa6a7a62f880791122261575b3048ac57dd72f300ba0827629ab8/cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a", size = 172955 }, + { url = "https://files.pythonhosted.org/packages/be/3e/0b197d1bfbf386a90786b251dbf2634a15f2ea3d4e4070e99c7d1c7689cf/cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1", size = 181616 }, + { url = "https://files.pythonhosted.org/packages/95/c8/ce05a6cba2bec12d4b28285e66c53cc88dd7385b102dea7231da3b74cfef/cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404", size = 182415 }, + { url = "https://files.pythonhosted.org/packages/18/6c/0406611f3d5aadf4c5b08f6c095d874aed8dfc2d3a19892707d72536d5dc/cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417", size = 176745 }, + { url = "https://files.pythonhosted.org/packages/58/ac/2a3ea436a6cbaa8f75ddcab39010e5e0817a18f26fef5d2fe2e0c7df3425/cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627", size = 443787 }, + { url = "https://files.pythonhosted.org/packages/b5/23/ea84dd4985649fcc179ba3a6c9390412e924d20b0244dc71a6545788f5a2/cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936", size = 466550 }, + { url = "https://files.pythonhosted.org/packages/36/44/124481b75d228467950b9e81d20ec963f33517ca551f08956f2838517ece/cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d", size = 474224 }, + { url = "https://files.pythonhosted.org/packages/e4/9a/7169ae3a67a7bb9caeb2249f0617ac1458df118305c53afa3dec4a9029cd/cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56", size = 457175 }, + { url = "https://files.pythonhosted.org/packages/9b/89/a31c81e36bbb793581d8bba4406a8aac4ba84b2559301c44eef81f4cf5df/cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e", size = 464825 }, + { url = "https://files.pythonhosted.org/packages/e0/80/52b71420d68c4be18873318f6735c742f1172bb3b18d23f0306e6444d410/cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc", size = 452727 }, + { url = "https://files.pythonhosted.org/packages/47/e3/b6832b1b9a1b6170c585ee2c2d30baf64d0a497c17e6623f42cfeb59c114/cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb", size = 476370 }, + { url = "https://files.pythonhosted.org/packages/4a/ac/a4046ab3d72536eff8bc30b39d767f69bd8be715c5e395b71cfca26f03d9/cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab", size = 172849 }, + { url = "https://files.pythonhosted.org/packages/5a/c7/694814b3757878b29da39bc2f0cf9d20295f4c1e0a0bde7971708d5f23f8/cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba", size = 181495 }, + { url = "https://files.pythonhosted.org/packages/22/04/1d10d5baf3faaae9b35f6c49bcf25c1be81ea68cc7ee6923206d02be85b0/cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956", size = 183322 }, + { url = "https://files.pythonhosted.org/packages/b4/f6/b28d2bfb5fca9e8f9afc9d05eae245bed9f6ba5c2897fefee7a9abeaf091/cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e", size = 177173 }, + { url = "https://files.pythonhosted.org/packages/9b/1a/575200306a3dfd9102ce573e7158d459a1bd7e44637e4f22a999c4fd64b1/cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e", size = 453846 }, + { url = "https://files.pythonhosted.org/packages/e4/c7/c09cc6fd1828ea950e60d44e0ef5ed0b7e3396fbfb856e49ca7d629b1408/cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2", size = 477041 }, + { url = "https://files.pythonhosted.org/packages/b4/5f/c6e7e8d80fbf727909e4b1b5b9352082fc1604a14991b1d536bfaee5a36c/cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357", size = 483787 }, + { url = "https://files.pythonhosted.org/packages/a3/81/5f5d61338951afa82ce4f0f777518708893b9420a8b309cc037fbf114e63/cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6", size = 469137 }, + { url = "https://files.pythonhosted.org/packages/09/d4/8759cc3b2222c159add8ce3af0089912203a31610f4be4c36f98e320b4c6/cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969", size = 477578 }, + { url = "https://files.pythonhosted.org/packages/4c/00/e17e2a8df0ff5aca2edd9eeebd93e095dd2515f2dd8d591d84a3233518f6/cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520", size = 487099 }, + { url = "https://files.pythonhosted.org/packages/c9/6e/751437067affe7ac0944b1ad4856ec11650da77f0dd8f305fae1117ef7bb/cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b", size = 173564 }, + { url = "https://files.pythonhosted.org/packages/e9/63/e285470a4880a4f36edabe4810057bd4b562c6ddcc165eacf9c3c7210b40/cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235", size = 181956 }, + { url = "https://files.pythonhosted.org/packages/39/44/4381b8d26e9cfa3e220e3c5386f443a10c6313a6ade7acb314b2bcc0a6ce/cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc", size = 182122 }, + { url = "https://files.pythonhosted.org/packages/7f/5a/39e212f99aa73660a1c523f6b7ddeb4e26f906faaa5088e97b617a89c7ae/cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0", size = 423842 }, + { url = "https://files.pythonhosted.org/packages/8b/5c/7f9cd1fb80512c9e16c90b29b26fea52977e9ab268321f64b42f4c8488a3/cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b", size = 446183 }, + { url = "https://files.pythonhosted.org/packages/f9/6c/af5f40c66aac38aa70abfa6f26e8296947a79ef373cb81a14c791c3da91d/cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c", size = 452938 }, + { url = "https://files.pythonhosted.org/packages/85/3e/a4e4857c2aae635195459679ac9daea296630c1d76351259eb3de3c18ed0/cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b", size = 434495 }, + { url = "https://files.pythonhosted.org/packages/f1/c9/326611aa83e16b13b6db4dbb73b5455c668159a003c4c2f0c3bcb2ddabaf/cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324", size = 444654 }, + { url = "https://files.pythonhosted.org/packages/40/c9/cfba735d9ed117471e32d7bce435dd49721261ae294277c64aa929ec9c9d/cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a", size = 172767 }, + { url = "https://files.pythonhosted.org/packages/4a/56/572f7f728b20e4d51766e63d7de811e45c7cae727dc1f769caad2973fb52/cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36", size = 181358 }, + { url = "https://files.pythonhosted.org/packages/9d/da/e6dbf22b66899419e66c501ae5f1cf3d69979d4c75ad30da683f60abba94/cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed", size = 182457 }, + { url = "https://files.pythonhosted.org/packages/20/3b/f95e667064141843843df8ca79dd49ba57bb7a7615d6d7d538531e45f002/cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2", size = 176810 }, + { url = "https://files.pythonhosted.org/packages/33/14/8398798ab001523f1abb2b4170a01bf2114588f3f1fa1f984b3f3bef107e/cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872", size = 422712 }, + { url = "https://files.pythonhosted.org/packages/50/bd/17a8f9ac569d328de304e7318d7707fcdb6f028bcc194d80cfc654902007/cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8", size = 444981 }, + { url = "https://files.pythonhosted.org/packages/69/46/8882b0405be4ac7db3fefa5a201f221acb54f27c76e584e23e9c62b68819/cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f", size = 451612 }, + { url = "https://files.pythonhosted.org/packages/ae/00/831d01e63288d1654ed3084a6ac8b0940de6dc0ada4ba71b830fff7a0088/cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4", size = 433351 }, + { url = "https://files.pythonhosted.org/packages/ea/ac/e9e77bc385729035143e54cc8c4785bd480eaca9df17565963556b0b7a93/cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098", size = 443366 }, + { url = "https://files.pythonhosted.org/packages/20/f8/5931cfb7a8cc15d224099cead5e5432efe729bd61abce72d9b3e51e5800b/cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000", size = 435991 }, + { url = "https://files.pythonhosted.org/packages/8c/54/82aa3c014760d5a6ddfde3253602f0ac1937dd504621d4139746f230a7b5/cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe", size = 465264 }, + { url = "https://files.pythonhosted.org/packages/04/a2/55f290ac034bd98c2a63e83be96925729cb2a70c8c42adc391ec5fbbaffd/cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4", size = 172894 }, + { url = "https://files.pythonhosted.org/packages/73/dd/15c6f32166f0c8f97d8aadee9ac8f096557899f4f21448d2feb74cf4f210/cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8", size = 181630 }, +] + +[[distribution]] +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 }, +] + +[[distribution]] +name = "cowsay" +version = "6.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/13/63c0a02c44024ee16f664e0b36eefeb22d54e93531630bd99e237986f534/cowsay-6.1-py3-none-any.whl", hash = "sha256:274b1e6fc1b966d53976333eb90ac94cb07a450a700b455af9fbdf882244b30a", size = 25560 }, +] + +[[distribution]] +name = "decorator" +version = "5.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/0c/8d907af351aa16b42caae42f9d6aa37b900c67308052d10fdce809f8d952/decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", size = 35016 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d5/50/83c593b07763e1161326b3b8c6686f0f4b0f24d5526546bee538c89837d6/decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186", size = 9073 }, +] + +[[distribution]] +name = "exceptiongroup" +version = "1.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a0/65/d66b7fbaef021b3c954b3bbb196d21d8a4b97918ea524f82cfae474215af/exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16", size = 28717 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/90/79fe92dd413a9cab314ef5c591b5aa9b9ba787ae4cadab75055b0ae00b33/exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad", size = 16458 }, +] + +[[distribution]] +name = "executing" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/08/41/85d2d28466fca93737592b7f3cc456d1cfd6bcd401beceeba17e8e792b50/executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147", size = 836501 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/80/03/6ea8b1b2a5ab40a7a60dc464d3daa7aa546e0a74d74a9f8ff551ea7905db/executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc", size = 24922 }, +] + +[[distribution]] +name = "ipython" +version = "8.17.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a9/e9/c83d1a5756bf44f1802045a54dacc910d3d254c5ec56040993978d8c1b8d/ipython-8.17.2.tar.gz", hash = "sha256:126bb57e1895594bb0d91ea3090bbd39384f6fe87c3d57fd558d0670f50339bb", size = 5486488 } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "exceptiongroup", marker = "python_version < '3.11'" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, + { name = "typing-extensions", marker = "python_version < '3.10'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/45/18f0dc2cbc3ee6680a004f620fb1400c6511ded0a76a2dd241813786ce73/ipython-8.17.2-py3-none-any.whl", hash = "sha256:1e4d1d666a023e3c93585ba0d8e962867f7a111af322efff6b9c58062b3e5444", size = 808414 }, +] + +[[distribution]] +name = "jedi" +version = "0.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/99/99b493cec4bf43176b678de30f81ed003fd6a647a301b9c927280c600f0a/jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", size = 1227821 } +dependencies = [ + { name = "parso" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/9f/bc63f0f0737ad7a60800bfd472a4836661adae21f9c2535f3957b1e54ceb/jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0", size = 1569361 }, +] + +[[distribution]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159 } +dependencies = [ + { name = "traitlets" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899 }, +] + +[[distribution]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650 }, +] + +[[distribution]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450 } +dependencies = [ + { name = "ptyprocess" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772 }, +] + +[[distribution]] +name = "prompt-toolkit" +version = "3.0.47" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/47/6d/0279b119dafc74c1220420028d490c4399b790fc1256998666e3a341879f/prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360", size = 425859 } +dependencies = [ + { name = "wcwidth" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/e8/23/22750c4b768f09386d1c3cc4337953e8936f48a888fa6dddfb669b2c9088/prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10", size = 386411 }, +] + +[[distribution]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993 }, +] + +[[distribution]] +name = "pure-eval" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/97/5a/0bc937c25d3ce4e0a74335222aee05455d6afa2888032185f8ab50cdf6fd/pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3", size = 19395 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2b/27/77f9d5684e6bce929f5cfe18d6cfbe5133013c06cb2fbf5933670e60761d/pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350", size = 11693 }, +] + +[[distribution]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552 }, +] + +[[distribution]] +name = "pygments" +version = "2.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/62/8336eff65bcbc8e4cb5d05b55faf041285951b6e80f33e2bff2024788f31/pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", size = 4891905 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f7/3f/01c8b82017c199075f8f788d0d906b9ffbbc5a47dc9918a945e13d5a2bda/pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a", size = 1205513 }, +] + +[[distribution]] +name = "regex" +version = "2023.10.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/38/49d968981b5ec35dbc0f742f8219acab179fc1567d9c22444152f950cf0d/regex-2023.10.3.tar.gz", hash = "sha256:3fef4f844d2290ee0ba57addcec17eec9e3df73f10a2748485dfd6a3a188cc0f", size = 394659 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/6b/4828fdbbabcb51986ddc1e7c618cf9dc8606f75c2f0cc381d3729cf31348/regex-2023.10.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4c34d4f73ea738223a094d8e0ffd6d2c1a1b4c175da34d6b0de3d8d69bee6bcc", size = 296398 }, + { url = "https://files.pythonhosted.org/packages/d1/f1/9c50c0e1e76234f05f876dd49df925dae49da7fb8cb152a429006c71f65b/regex-2023.10.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a8f4e49fc3ce020f65411432183e6775f24e02dff617281094ba6ab079ef0915", size = 291008 }, + { url = "https://files.pythonhosted.org/packages/5d/ba/a9b104f3e78d9a08c093c325419ddd4a03fc04e9f391f8cf580cdf21a0fe/regex-2023.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cd1bccf99d3ef1ab6ba835308ad85be040e6a11b0977ef7ea8c8005f01a3c29", size = 774078 }, + { url = "https://files.pythonhosted.org/packages/ba/88/ecc84fcd7433ea3d4612a64e8a8f57d44dbb5a6591d359596df1682ca5c8/regex-2023.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:81dce2ddc9f6e8f543d94b05d56e70d03a0774d32f6cca53e978dc01e4fc75b8", size = 814891 }, + { url = "https://files.pythonhosted.org/packages/ce/eb/18fe76b9c161abb23d2c8e1e3eefd24849018e5e8be01202fb278b35e8f6/regex-2023.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c6b4d23c04831e3ab61717a707a5d763b300213db49ca680edf8bf13ab5d91b", size = 800507 }, + { url = "https://files.pythonhosted.org/packages/8f/3e/4b8b40eb3c80aeaf360f0361d956d129bb3d23b2a3ecbe3a04a8f3bdd6d3/regex-2023.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c15ad0aee158a15e17e0495e1e18741573d04eb6da06d8b84af726cfc1ed02ee", size = 773936 }, + { url = "https://files.pythonhosted.org/packages/4d/b0/1e937cacdf8525d96ef9c0990d0e607c254a4f112ccc32c65da1f4550366/regex-2023.10.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6239d4e2e0b52c8bd38c51b760cd870069f0bdf99700a62cd509d7a031749a55", size = 762975 }, + { url = "https://files.pythonhosted.org/packages/bd/79/ced572f3316e2a1ddfec801d69c167ab3c2d5f76c12918b4f0de147b3180/regex-2023.10.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4a8bf76e3182797c6b1afa5b822d1d5802ff30284abe4599e1247be4fd6b03be", size = 690343 }, + { url = "https://files.pythonhosted.org/packages/f2/02/8729f600542a37f6e9c17eaee8c53d65d66966fe67b4bdbadea80b0ae3b2/regex-2023.10.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d9c727bbcf0065cbb20f39d2b4f932f8fa1631c3e01fcedc979bd4f51fe051c5", size = 743877 }, + { url = "https://files.pythonhosted.org/packages/35/41/f04d9ba6978246f9e4dd79fe727e42ebd08d0e1901ef0600c8604ddfa584/regex-2023.10.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:3ccf2716add72f80714b9a63899b67fa711b654be3fcdd34fa391d2d274ce767", size = 731360 }, + { url = "https://files.pythonhosted.org/packages/46/f7/4447642811a77604b231ec178c5e6cbed7238d0d4fab1d20cb737fb8668b/regex-2023.10.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:107ac60d1bfdc3edb53be75e2a52aff7481b92817cfdddd9b4519ccf0e54a6ff", size = 764014 }, + { url = "https://files.pythonhosted.org/packages/a2/f3/39b16779acf180e4ae20a2aaf387313800f3137fe44561a4e36f5800599b/regex-2023.10.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:00ba3c9818e33f1fa974693fb55d24cdc8ebafcb2e4207680669d8f8d7cca79a", size = 768557 }, + { url = "https://files.pythonhosted.org/packages/e2/65/2a6fe79b0588b347c20d47dbab76bda5551e2b506b2f86d98fbe8232ea47/regex-2023.10.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f0a47efb1dbef13af9c9a54a94a0b814902e547b7f21acb29434504d18f36e3a", size = 744686 }, + { url = "https://files.pythonhosted.org/packages/2b/86/08f13773d36c660b0bf19103a33fac90e8529f4b2cdaf3f90820ee047f55/regex-2023.10.3-cp310-cp310-win32.whl", hash = "sha256:36362386b813fa6c9146da6149a001b7bd063dabc4d49522a1f7aa65b725c7ec", size = 257627 }, + { url = "https://files.pythonhosted.org/packages/33/03/91c9509b43154795fb848a4cf8cef5b37302b3b3ccf8a9763046ea528c6b/regex-2023.10.3-cp310-cp310-win_amd64.whl", hash = "sha256:c65a3b5330b54103e7d21cac3f6bf3900d46f6d50138d73343d9e5b2900b2353", size = 269555 }, + { url = "https://files.pythonhosted.org/packages/27/b8/fde0e99442b328d159bd0b2c0ff5401e1f1839e7a8d7339308b3915c7faa/regex-2023.10.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90a79bce019c442604662d17bf69df99090e24cdc6ad95b18b6725c2988a490e", size = 296433 }, + { url = "https://files.pythonhosted.org/packages/4d/d3/38b09813a32618acd437906c4d0194119e27139dbcd7486e69d58e375a27/regex-2023.10.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7964c2183c3e6cce3f497e3a9f49d182e969f2dc3aeeadfa18945ff7bdd7051", size = 291018 }, + { url = "https://files.pythonhosted.org/packages/be/5d/bf0e6eca09839b82ac640adabad2560cc39a69bf802c6d2759e52c113f7e/regex-2023.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ef80829117a8061f974b2fda8ec799717242353bff55f8a29411794d635d964", size = 783848 }, + { url = "https://files.pythonhosted.org/packages/a3/21/471fa60fba6169e5a766ccab488e79352179c2e33b40a1dc1d8da9e0b1ee/regex-2023.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5addc9d0209a9afca5fc070f93b726bf7003bd63a427f65ef797a931782e7edc", size = 823425 }, + { url = "https://files.pythonhosted.org/packages/07/69/b9e3cd37f2babe93c63b2d6157a2c17320b3ba9a3ebd5156131dd7a869b9/regex-2023.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c148bec483cc4b421562b4bcedb8e28a3b84fcc8f0aa4418e10898f3c2c0eb9b", size = 810134 }, + { url = "https://files.pythonhosted.org/packages/f2/b8/b1ec82fce93064a73ba67f2bb158ec9cac4a0e8f0b6942268ec963947329/regex-2023.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d1f21af4c1539051049796a0f50aa342f9a27cde57318f2fc41ed50b0dbc4ac", size = 785086 }, + { url = "https://files.pythonhosted.org/packages/6f/17/d2b5b4adf638752b8cc999c81eeb22fd7288b4561aea328ca04f5105d800/regex-2023.10.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0b9ac09853b2a3e0d0082104036579809679e7715671cfbf89d83c1cb2a30f58", size = 772804 }, + { url = "https://files.pythonhosted.org/packages/71/44/1b089d021e9440c6f7a8c917d89d0bc174399add651d601648c0a221c165/regex-2023.10.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ebedc192abbc7fd13c5ee800e83a6df252bec691eb2c4bedc9f8b2e2903f5e2a", size = 749930 }, + { url = "https://files.pythonhosted.org/packages/41/ff/e055e5d1d08a659e6a716ab2250efba07aeb58fa3c82ac4dc845edea2240/regex-2023.10.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:d8a993c0a0ffd5f2d3bda23d0cd75e7086736f8f8268de8a82fbc4bd0ac6791e", size = 738403 }, + { url = "https://files.pythonhosted.org/packages/73/ae/c595838c8bbc7d87ab7b4034c2676faca7271653a62d5f1f35f52ed14112/regex-2023.10.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:be6b7b8d42d3090b6c80793524fa66c57ad7ee3fe9722b258aec6d0672543fd0", size = 770431 }, + { url = "https://files.pythonhosted.org/packages/dd/35/c0cb2cb9ae53c55348934d55adf1efbe72548340d88e9885dac8be4ec9d4/regex-2023.10.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4023e2efc35a30e66e938de5aef42b520c20e7eda7bb5fb12c35e5d09a4c43f6", size = 776306 }, + { url = "https://files.pythonhosted.org/packages/a0/75/a428ac7c0adb4fa470fc813c63cf0c9f5f795c3456593cf061a802188768/regex-2023.10.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0d47840dc05e0ba04fe2e26f15126de7c755496d5a8aae4a08bda4dd8d646c54", size = 752920 }, + { url = "https://files.pythonhosted.org/packages/94/9e/c0e6271d7c6a3542e9e0f0710c4a5de19f18f7728e9619d6aa78580d7844/regex-2023.10.3-cp311-cp311-win32.whl", hash = "sha256:9145f092b5d1977ec8c0ab46e7b3381b2fd069957b9862a43bd383e5c01d18c2", size = 257633 }, + { url = "https://files.pythonhosted.org/packages/b8/ad/3398312096118c4e62a5827664e52a04d5068e84d04142dd4a0da8a567ae/regex-2023.10.3-cp311-cp311-win_amd64.whl", hash = "sha256:b6104f9a46bd8743e4f738afef69b153c4b8b592d35ae46db07fc28ae3d5fb7c", size = 269566 }, + { url = "https://files.pythonhosted.org/packages/59/f6/b719df3bc93004bb0c646d4fddd769a018ad2eff7f149f5c72770faedf7a/regex-2023.10.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff507ae210371d4b1fe316d03433ac099f184d570a1a611e541923f78f05037", size = 298080 }, + { url = "https://files.pythonhosted.org/packages/c6/a9/d543130248a2ceba74787518aea5d4a9f9373fb09fa860283fb0afa2718b/regex-2023.10.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:be5e22bbb67924dea15039c3282fa4cc6cdfbe0cbbd1c0515f9223186fc2ec5f", size = 292223 }, + { url = "https://files.pythonhosted.org/packages/38/a4/645e381727142609772a37c50d2f4b0316bbfa40a6e5b1ad27f8493767f4/regex-2023.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a992f702c9be9c72fa46f01ca6e18d131906a7180950958f766c2aa294d4b41", size = 786041 }, + { url = "https://files.pythonhosted.org/packages/09/00/55a25fa71f0dccc133f6bbe2977bad2139324cfe9c651060d0d5fb3436e0/regex-2023.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7434a61b158be563c1362d9071358f8ab91b8d928728cd2882af060481244c9e", size = 829502 }, + { url = "https://files.pythonhosted.org/packages/29/9f/e9899da293d57a2924d4149650284105020edf6aeaa578c20d81ba3bda16/regex-2023.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c2169b2dcabf4e608416f7f9468737583ce5f0a6e8677c4efbf795ce81109d7c", size = 814706 }, + { url = "https://files.pythonhosted.org/packages/0a/9e/f5bac36b963741bf3abbcd719f7a7375b95486efcb27c1e2faaaead26c67/regex-2023.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a9e908ef5889cda4de038892b9accc36d33d72fb3e12c747e2799a0e806ec841", size = 789090 }, + { url = "https://files.pythonhosted.org/packages/ad/d6/923cce27d7915c69a84a27dabc06b5585ca995714e3a29cf704a3ddaa266/regex-2023.10.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12bd4bc2c632742c7ce20db48e0d99afdc05e03f0b4c1af90542e05b809a03d9", size = 776997 }, + { url = "https://files.pythonhosted.org/packages/b6/d5/d6e84e0bd284d51219acdc2b2d374a9c07ef5ca3ad6383fd94432635d651/regex-2023.10.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:bc72c231f5449d86d6c7d9cc7cd819b6eb30134bb770b8cfdc0765e48ef9c420", size = 751243 }, + { url = "https://files.pythonhosted.org/packages/70/2e/cf011580fe8ce02081b3759fe5860b642c56228a290859923e9c849397d5/regex-2023.10.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bce8814b076f0ce5766dc87d5a056b0e9437b8e0cd351b9a6c4e1134a7dfbda9", size = 742464 }, + { url = "https://files.pythonhosted.org/packages/39/50/2bcb063dca682c18bf849ff901d41ee8cf8fe1a72131d652853173bf4916/regex-2023.10.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:ba7cd6dc4d585ea544c1412019921570ebd8a597fabf475acc4528210d7c4a6f", size = 775150 }, + { url = "https://files.pythonhosted.org/packages/e8/ee/d649947e9b74546bec3fb82ac71dba990abbe683754d1fc4062a5bd47838/regex-2023.10.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b0c7d2f698e83f15228ba41c135501cfe7d5740181d5903e250e47f617eb4292", size = 779318 }, + { url = "https://files.pythonhosted.org/packages/0c/50/7b1a37d25b5479f1ce8800195e83573a499156dfe957abfc2acdd8238f08/regex-2023.10.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5a8f91c64f390ecee09ff793319f30a0f32492e99f5dc1c72bc361f23ccd0a9a", size = 759707 }, + { url = "https://files.pythonhosted.org/packages/03/42/04e85a50bca5e45925668198f0c69699b4b5f6dbec47dd24773a0c0ed7ce/regex-2023.10.3-cp312-cp312-win32.whl", hash = "sha256:ad08a69728ff3c79866d729b095872afe1e0557251da4abb2c5faff15a91d19a", size = 258015 }, + { url = "https://files.pythonhosted.org/packages/d3/10/6f2d5f8635d7714ad97ce6ade7a643358c4f3e45cde4ed12b7150734a8f3/regex-2023.10.3-cp312-cp312-win_amd64.whl", hash = "sha256:39cdf8d141d6d44e8d5a12a8569d5a227f645c87df4f92179bd06e2e2705e76b", size = 268991 }, + { url = "https://files.pythonhosted.org/packages/31/03/5bce12d28522befd162724eb88826f01b0e4c7bf2eeca0eda30f9b4a8db7/regex-2023.10.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4a3ee019a9befe84fa3e917a2dd378807e423d013377a884c1970a3c2792d293", size = 296889 }, + { url = "https://files.pythonhosted.org/packages/d7/28/e4c7b2efd70d97dea56b292cbab9f7f6e77072e71b7ff3e3e0d6e4efe0f6/regex-2023.10.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76066d7ff61ba6bf3cb5efe2428fc82aac91802844c022d849a1f0f53820502d", size = 760321 }, + { url = "https://files.pythonhosted.org/packages/8f/f5/e7a9b06f5feb88e723295b31250254308d2c60cb47e6b2c1350b496660ea/regex-2023.10.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe50b61bab1b1ec260fa7cd91106fa9fece57e6beba05630afe27c71259c59b", size = 801224 }, + { url = "https://files.pythonhosted.org/packages/32/ea/bd36e51a753ca424877e57f94a4131444449a74d96dec654ce8dae1fbd28/regex-2023.10.3-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9fd88f373cb71e6b59b7fa597e47e518282455c2734fd4306a05ca219a1991b0", size = 786488 }, + { url = "https://files.pythonhosted.org/packages/ec/2d/40500c0d370a0633dfc7da82cc15f34bb066af6a485c9e1bc29174c84578/regex-2023.10.3-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3ab05a182c7937fb374f7e946f04fb23a0c0699c0450e9fb02ef567412d2fa3", size = 761585 }, + { url = "https://files.pythonhosted.org/packages/79/0b/7566b0eb74b30fedc1f24445584781550f82630f3fa81c62acb6e6c6936d/regex-2023.10.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dac37cf08fcf2094159922edc7a2784cfcc5c70f8354469f79ed085f0328ebdf", size = 749048 }, + { url = "https://files.pythonhosted.org/packages/71/0a/e802ea7324e7e9bee17fd7ef65ad5e1363c3091a223dc93c3fc14ef4980f/regex-2023.10.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e54ddd0bb8fb626aa1f9ba7b36629564544954fff9669b15da3610c22b9a0991", size = 681444 }, + { url = "https://files.pythonhosted.org/packages/fe/9c/01bf66e494cbf36aadf49483fd2197192a49664560d6e96f7188940c78f9/regex-2023.10.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:3367007ad1951fde612bf65b0dffc8fd681a4ab98ac86957d16491400d661302", size = 732601 }, + { url = "https://files.pythonhosted.org/packages/fd/6c/421e77fab803c5db12134601784dab52ec2741adfe64bc700edb37968e2e/regex-2023.10.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:16f8740eb6dbacc7113e3097b0a36065a02e37b47c936b551805d40340fb9971", size = 724187 }, + { url = "https://files.pythonhosted.org/packages/e8/9f/8f22792819e6bf5cf273b161babae14d0ed3bd3698fd8f2e222a4207866c/regex-2023.10.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:f4f2ca6df64cbdd27f27b34f35adb640b5d2d77264228554e68deda54456eb11", size = 755769 }, + { url = "https://files.pythonhosted.org/packages/42/ba/596041299ff79037ac45a44c4c9b7256c0be61b8adcd299c263ecec9822c/regex-2023.10.3-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:39807cbcbe406efca2a233884e169d056c35aa7e9f343d4e78665246a332f597", size = 757377 }, + { url = "https://files.pythonhosted.org/packages/ae/91/007ca3482b670efb677b7654fd12bbe9d1ebda2ee098795902829e1ff254/regex-2023.10.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:7eece6fbd3eae4a92d7c748ae825cbc1ee41a89bb1c3db05b5578ed3cfcfd7cb", size = 733512 }, + { url = "https://files.pythonhosted.org/packages/74/79/192678117e88e454ce65d2cd99b1177478e986086bd586c756511c4ff4f3/regex-2023.10.3-cp37-cp37m-win32.whl", hash = "sha256:ce615c92d90df8373d9e13acddd154152645c0dc060871abf6bd43809673d20a", size = 257313 }, + { url = "https://files.pythonhosted.org/packages/84/5d/bbeae673d7fd9b3846c5adf53257040cdeefe92a62900eb42be079a293f5/regex-2023.10.3-cp37-cp37m-win_amd64.whl", hash = "sha256:0f649fa32fe734c4abdfd4edbb8381c74abf5f34bc0b3271ce687b23729299ed", size = 269916 }, + { url = "https://files.pythonhosted.org/packages/25/62/2fb4e702f6c1afdc647c1313f54494a6647d3f8b9c76877b6cd82d280f04/regex-2023.10.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9b98b7681a9437262947f41c7fac567c7e1f6eddd94b0483596d320092004533", size = 296344 }, + { url = "https://files.pythonhosted.org/packages/2c/74/ea77ab33736614442585bf8944feb95ffcf1cb9e8ef580aada6f1e5ba73a/regex-2023.10.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:91dc1d531f80c862441d7b66c4505cd6ea9d312f01fb2f4654f40c6fdf5cc37a", size = 290982 }, + { url = "https://files.pythonhosted.org/packages/9b/8b/5a65cb80a5ae3902f5cfff0f67e3e17841a204a56c1324c9c2ab98c4df1b/regex-2023.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82fcc1f1cc3ff1ab8a57ba619b149b907072e750815c5ba63e7aa2e1163384a4", size = 776823 }, + { url = "https://files.pythonhosted.org/packages/94/71/37e7de346b52251c5a1159daa18ce29fd9ce96620835af7c92bb91650770/regex-2023.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7979b834ec7a33aafae34a90aad9f914c41fd6eaa8474e66953f3f6f7cbd4368", size = 818076 }, + { url = "https://files.pythonhosted.org/packages/fa/8b/e4cd73294688ca30ef8ea46d597233dbb56350c8b04dfc3a462cc129f62f/regex-2023.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ef71561f82a89af6cfcbee47f0fabfdb6e63788a9258e913955d89fdd96902ab", size = 802324 }, + { url = "https://files.pythonhosted.org/packages/79/33/67c4ed826f5227655225c3feaaecd15afb8453e827334ddae95a7fba07ac/regex-2023.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd829712de97753367153ed84f2de752b86cd1f7a88b55a3a775eb52eafe8a94", size = 776991 }, + { url = "https://files.pythonhosted.org/packages/60/1c/945c8ef0a6a0012d22d818592c129cc21d4ecffd56815d05fe58d4e2f901/regex-2023.10.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:00e871d83a45eee2f8688d7e6849609c2ca2a04a6d48fba3dff4deef35d14f07", size = 764435 }, + { url = "https://files.pythonhosted.org/packages/02/52/04ea087f6080128423878661bedd48d39079c23faa14ad5d4a598c32cb60/regex-2023.10.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:706e7b739fdd17cb89e1fbf712d9dc21311fc2333f6d435eac2d4ee81985098c", size = 695742 }, + { url = "https://files.pythonhosted.org/packages/97/b9/b1d86292b8a42029e296ee5cc6a3c93c0ff1dcd8925b05ca693607d75c7e/regex-2023.10.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:cc3f1c053b73f20c7ad88b0d1d23be7e7b3901229ce89f5000a8399746a6e039", size = 748460 }, + { url = "https://files.pythonhosted.org/packages/38/b6/714244a989b6cec51109d1ba2ee89ae81f901e2f206b49716d4b87616523/regex-2023.10.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:6f85739e80d13644b981a88f529d79c5bdf646b460ba190bffcaf6d57b2a9863", size = 738056 }, + { url = "https://files.pythonhosted.org/packages/91/e2/344347e19232a7b3002f1242527d6607ca71c78498b4cbd2af8e8b585354/regex-2023.10.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:741ba2f511cc9626b7561a440f87d658aabb3d6b744a86a3c025f866b4d19e7f", size = 769009 }, + { url = "https://files.pythonhosted.org/packages/2b/ca/b6691a334caa523ef0f668ef00797b7d35f49d2a9bfa045b800d75de848d/regex-2023.10.3-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:e77c90ab5997e85901da85131fd36acd0ed2221368199b65f0d11bca44549711", size = 771171 }, + { url = "https://files.pythonhosted.org/packages/5c/52/1ffedb230daba57c34e71064486a7bd0720401235bf83254dab6905afdf1/regex-2023.10.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:979c24cbefaf2420c4e377ecd1f165ea08cc3d1fbb44bdc51bccbbf7c66a2cb4", size = 752361 }, + { url = "https://files.pythonhosted.org/packages/32/22/88403f4d2398105965be7d43438a9c220ca8324c6da7047943e43bd8fd42/regex-2023.10.3-cp38-cp38-win32.whl", hash = "sha256:58837f9d221744d4c92d2cf7201c6acd19623b50c643b56992cbd2b745485d3d", size = 257669 }, + { url = "https://files.pythonhosted.org/packages/7d/38/dcd673b81c2b4930bf39d970decff57ba48e0aee3028364897830ca9cc8e/regex-2023.10.3-cp38-cp38-win_amd64.whl", hash = "sha256:c55853684fe08d4897c37dfc5faeff70607a5f1806c8be148f1695be4a63414b", size = 269585 }, + { url = "https://files.pythonhosted.org/packages/af/14/97ba8f3eb4275b2fdeae73d79b74bd0b8995c6e22c7aa7e90a547c19cf90/regex-2023.10.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2c54e23836650bdf2c18222c87f6f840d4943944146ca479858404fedeb9f9af", size = 296389 }, + { url = "https://files.pythonhosted.org/packages/cd/98/999f0456bdb4124b3d0a7f1d8b6d50979536f5df9856e597580dd9a6d3ff/regex-2023.10.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:69c0771ca5653c7d4b65203cbfc5e66db9375f1078689459fe196fe08b7b4930", size = 291011 }, + { url = "https://files.pythonhosted.org/packages/ed/26/4d0153b41b5aed2530a1cf43bff05e971df5566da188f43cf8dc663d3d5d/regex-2023.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ac965a998e1388e6ff2e9781f499ad1eaa41e962a40d11c7823c9952c77123e", size = 773529 }, + { url = "https://files.pythonhosted.org/packages/f5/8b/6ea337109965f7f2ef9ecc7828b1a0127106e6c1ab8c42dd631fbff7c783/regex-2023.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c0e8fae5b27caa34177bdfa5a960c46ff2f78ee2d45c6db15ae3f64ecadde14", size = 814354 }, + { url = "https://files.pythonhosted.org/packages/87/48/d390943a73ee7aca0c8547dcc3380fd056884389ba7b0b95a7ea4de8cb27/regex-2023.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6c56c3d47da04f921b73ff9415fbaa939f684d47293f071aa9cbb13c94afc17d", size = 799459 }, + { url = "https://files.pythonhosted.org/packages/54/71/b85c050a8b6a552261e9deae23ba20099852cfbcc9819a628ce64f5a0db6/regex-2023.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ef1e014eed78ab650bef9a6a9cbe50b052c0aebe553fb2881e0453717573f52", size = 773340 }, + { url = "https://files.pythonhosted.org/packages/e8/ed/2d5446bb354ec39d399b55c79618aa625106fdc2e98b72d4082822474ce9/regex-2023.10.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d29338556a59423d9ff7b6eb0cb89ead2b0875e08fe522f3e068b955c3e7b59b", size = 762535 }, + { url = "https://files.pythonhosted.org/packages/b8/93/e3aa510727e9747c8dc3314c7449befb7c055a4ab557590f2817bf43c9fd/regex-2023.10.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9c6d0ced3c06d0f183b73d3c5920727268d2201aa0fe6d55c60d68c792ff3588", size = 689767 }, + { url = "https://files.pythonhosted.org/packages/a2/68/c0b9e7d6fa92e4b11f4f47ab31e4604875cdc413a23d751ba12585ddf8d5/regex-2023.10.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:994645a46c6a740ee8ce8df7911d4aee458d9b1bc5639bc968226763d07f00fa", size = 743621 }, + { url = "https://files.pythonhosted.org/packages/71/10/7e4f345adf2f61665b41067490cf633cdaa771443b3ca2cd032ffb49abee/regex-2023.10.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:66e2fe786ef28da2b28e222c89502b2af984858091675044d93cb50e6f46d7af", size = 730687 }, + { url = "https://files.pythonhosted.org/packages/7b/91/daf3a5ecd6718700a5f3c2ca44fbe72b2c9659459e82673f071a07c61117/regex-2023.10.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:11175910f62b2b8c055f2b089e0fedd694fe2be3941b3e2633653bc51064c528", size = 763498 }, + { url = "https://files.pythonhosted.org/packages/b9/e3/0c41fddaa25801889ea26330e992da77c259ad399b9fdb6722add6ad3856/regex-2023.10.3-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:06e9abc0e4c9ab4779c74ad99c3fc10d3967d03114449acc2c2762ad4472b8ca", size = 768103 }, + { url = "https://files.pythonhosted.org/packages/ed/72/4399629b7ccb2c9380638f6cffd716d1f2aa02c840253cee41389ecee117/regex-2023.10.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:fb02e4257376ae25c6dd95a5aec377f9b18c09be6ebdefa7ad209b9137b73d48", size = 744484 }, + { url = "https://files.pythonhosted.org/packages/b0/b0/5e991527d2002779746061d2c23291cf97c18b7527c4d3aecd181421126a/regex-2023.10.3-cp39-cp39-win32.whl", hash = "sha256:3b2c3502603fab52d7619b882c25a6850b766ebd1b18de3df23b2f939360e1bd", size = 257667 }, + { url = "https://files.pythonhosted.org/packages/fc/85/0d1038f068900896a8590d6d0da198b90d31f731a39166a432aa2b92249b/regex-2023.10.3-cp39-cp39-win_amd64.whl", hash = "sha256:adbccd17dcaff65704c856bd29951c58a1bd4b2b0f8ad6b826dbd543fe740988", size = 269592 }, +] + +[[distribution]] +name = "rules-pycross-smoke" +version = "0.1" +source = { editable = "." } +dependencies = [ + { name = "cowsay" }, + { name = "ipython" }, + { name = "regex" }, + { name = "setuptools" }, + { name = "wheel" }, + { name = "zstandard" }, +] + +[[distribution]] +name = "setuptools" +version = "68.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ef/cc/93f7213b2ab5ed383f98ce8020e632ef256b406b8569606c3f160ed8e1c9/setuptools-68.2.2.tar.gz", hash = "sha256:4ac1475276d2f1c48684874089fefcd83bd7162ddaafb81fac866ba0db282a87", size = 2203338 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/26/7945080113158354380a12ce26873dd6c1ebd88d47f5bc24e2c5bb38c16a/setuptools-68.2.2-py3-none-any.whl", hash = "sha256:b454a35605876da60632df1a60f736524eb73cc47bbc9f3f1ef1b644de74fd2a", size = 807864 }, +] + +[[distribution]] +name = "six" +version = "1.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/71/39/171f1c67cd00715f190ba0b100d606d440a28c93c7714febeca8b79af85e/six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", size = 34041 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/5a/e7c31adbe875f2abbb91bd84cf2dc52d792b5a01506781dbcf25c91daf11/six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254", size = 11053 }, +] + +[[distribution]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707 } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521 }, +] + +[[distribution]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359 }, +] + +[[distribution]] +name = "typing-extensions" +version = "4.12.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/df/db/f35a00659bc03fec321ba8bce9420de607a1d37f8342eee1863174c69557/typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8", size = 85321 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/9f/ad63fc0248c5379346306f8668cda6e2e2e9c95e01216d2b8ffd9ff037d0/typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", size = 37438 }, +] + +[[distribution]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166 }, +] + +[[distribution]] +name = "wheel" +version = "0.41.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fb/d0/0b4c18a0b85c20233b0c3bc33f792aefd7f12a5832b4da77419949ff6fd9/wheel-0.41.3.tar.gz", hash = "sha256:4d4987ce51a49370ea65c0bfd2234e8ce80a12780820d9dc462597a6e60d0841", size = 98880 } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fa/7f/4c07234086edbce4a0a446209dc0cb08a19bb206a3ea53b2f56a403f983b/wheel-0.41.3-py3-none-any.whl", hash = "sha256:488609bc63a29322326e05560731bf7bfea8e48ad646e1f5e40d366607de0942", size = 65801 }, +] + +[[distribution]] +name = "zstandard" +version = "0.22.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5d/91/2162ab4239b3bd6743e8e407bc2442fca0d326e2d77b3f4a88d90ad5a1fa/zstandard-0.22.0.tar.gz", hash = "sha256:8226a33c542bcb54cd6bd0a366067b610b41713b64c9abec1bc4533d69f51e70", size = 660738 } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation == 'PyPy'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/a4/b7cc74e836ec006427d18439c12b7898697c1eae91b06ffdfa63da8cd041/zstandard-0.22.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:275df437ab03f8c033b8a2c181e51716c32d831082d93ce48002a5227ec93019", size = 920944 }, + { url = "https://files.pythonhosted.org/packages/fc/e5/a1fa6f70764777553cb8ab668690ba793ebf512b3d415e28720d2275d445/zstandard-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2ac9957bc6d2403c4772c890916bf181b2653640da98f32e04b96e4d6fb3252a", size = 703353 }, + { url = "https://files.pythonhosted.org/packages/8e/3b/0284ed7b2612f793d2490339c1b772232c04a6f20dbbdec050020bd730b2/zstandard-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe3390c538f12437b859d815040763abc728955a52ca6ff9c5d4ac707c4ad98e", size = 4914750 }, + { url = "https://files.pythonhosted.org/packages/c9/79/07f6d2670fa2708ae3b79aabb82da78e9cbdb08d9bafadf8638d356775ff/zstandard-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1958100b8a1cc3f27fa21071a55cb2ed32e9e5df4c3c6e661c193437f171cba2", size = 5430445 }, + { url = "https://files.pythonhosted.org/packages/28/fa/60d35409132b101694943043385ecd610c23f30148e8a15af84c46844b03/zstandard-0.22.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:93e1856c8313bc688d5df069e106a4bc962eef3d13372020cc6e3ebf5e045202", size = 4843872 }, + { url = "https://files.pythonhosted.org/packages/77/2a/910576262607524ff203f5fa849329f8fad6f67b7804a5ef00019f98c390/zstandard-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:1a90ba9a4c9c884bb876a14be2b1d216609385efb180393df40e5172e7ecf356", size = 4921277 }, + { url = "https://files.pythonhosted.org/packages/95/6b/aea6911a0dbbd5e67dd4e3db8f6b9b594ba05a0ae62f6f3c88cb609a7878/zstandard-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3db41c5e49ef73641d5111554e1d1d3af106410a6c1fb52cf68912ba7a343a0d", size = 5444761 }, + { url = "https://files.pythonhosted.org/packages/57/ab/4e4207c78202dccc18be4a22f3ab6b7253bc705c7132385117b5969d9e84/zstandard-0.22.0-cp310-cp310-win32.whl", hash = "sha256:d8593f8464fb64d58e8cb0b905b272d40184eac9a18d83cf8c10749c3eafcd7e", size = 442565 }, + { url = "https://files.pythonhosted.org/packages/4f/2b/ba21c97380fc1b6c9a2c44b432a116599147171c24c084ea0ba6507a2107/zstandard-0.22.0-cp310-cp310-win_amd64.whl", hash = "sha256:f1a4b358947a65b94e2501ce3e078bbc929b039ede4679ddb0460829b12f7375", size = 511644 }, + { url = "https://files.pythonhosted.org/packages/32/41/80fc08ed96e68df920d28592710f5ed96fb288fda1fbb4b6aee5fdbaa5f6/zstandard-0.22.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:589402548251056878d2e7c8859286eb91bd841af117dbe4ab000e6450987e08", size = 921016 }, + { url = "https://files.pythonhosted.org/packages/54/fc/c1b1a1e140451f3362789f546731b3ef36c78668be19d7fc6fbd4326b535/zstandard-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a97079b955b00b732c6f280d5023e0eefe359045e8b83b08cf0333af9ec78f26", size = 703352 }, + { url = "https://files.pythonhosted.org/packages/68/fb/0a9389ee8ccc532ac4567562c7746bd7537d16bc5b079b2696fe3c510c37/zstandard-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:445b47bc32de69d990ad0f34da0e20f535914623d1e506e74d6bc5c9dc40bb09", size = 4918211 }, + { url = "https://files.pythonhosted.org/packages/80/6a/f8a618f84aafb9c373a959e7e51ad34bda73f1d99cd856c05c8f0b78e87f/zstandard-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33591d59f4956c9812f8063eff2e2c0065bc02050837f152574069f5f9f17775", size = 5433363 }, + { url = "https://files.pythonhosted.org/packages/a4/e1/0b29be2d3a8d86053f284add5a0b4174c820fefc96183b01d5cbcedd498d/zstandard-0.22.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:888196c9c8893a1e8ff5e89b8f894e7f4f0e64a5af4d8f3c410f0319128bb2f8", size = 4847234 }, + { url = "https://files.pythonhosted.org/packages/55/0b/b23b1a6e4d4525f663162344d4896f396267e7f65607f16f7a62e1862a23/zstandard-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:53866a9d8ab363271c9e80c7c2e9441814961d47f88c9bc3b248142c32141d94", size = 4923512 }, + { url = "https://files.pythonhosted.org/packages/9f/da/e16b2a5613141aaa719e4b09cdadf5eb3fb099311ffc8c0b13785bdcbe1a/zstandard-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:4ac59d5d6910b220141c1737b79d4a5aa9e57466e7469a012ed42ce2d3995e88", size = 5447292 }, + { url = "https://files.pythonhosted.org/packages/ff/1d/ecca5dee2d173b3b70fa8d6bdeec17f9a875aa6fdac4a6bfaadf7c9668a1/zstandard-0.22.0-cp311-cp311-win32.whl", hash = "sha256:2b11ea433db22e720758cba584c9d661077121fcf60ab43351950ded20283440", size = 442566 }, + { url = "https://files.pythonhosted.org/packages/8a/bc/878a5b8f413d5fe902842fde08ecf317d3979c9728135034a519c409ce3f/zstandard-0.22.0-cp311-cp311-win_amd64.whl", hash = "sha256:11f0d1aab9516a497137b41e3d3ed4bbf7b2ee2abc79e5c8b010ad286d7464bd", size = 511638 }, + { url = "https://files.pythonhosted.org/packages/0f/f9/6b531e83f2e61bb9d66508113fd68557d990639be3dd37116af272932614/zstandard-0.22.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:6c25b8eb733d4e741246151d895dd0308137532737f337411160ff69ca24f93a", size = 920922 }, + { url = "https://files.pythonhosted.org/packages/7d/80/9e40e57ba17dbbf6c55bcf0ac4ee533c367285209f309bdd9ab290c40536/zstandard-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f9b2cde1cd1b2a10246dbc143ba49d942d14fb3d2b4bccf4618d475c65464912", size = 703142 }, + { url = "https://files.pythonhosted.org/packages/47/44/be2d67304ba9bf4694ffcaa99d146814d70c4cb0bfc00e0e86fdfae66a31/zstandard-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a88b7df61a292603e7cd662d92565d915796b094ffb3d206579aaebac6b85d5f", size = 4918778 }, + { url = "https://files.pythonhosted.org/packages/e5/01/080939755ca12ebbb7fc38b6f4ddecd5e8c416d571d4927ece1360baba2c/zstandard-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:466e6ad8caefb589ed281c076deb6f0cd330e8bc13c5035854ffb9c2014b118c", size = 5426393 }, + { url = "https://files.pythonhosted.org/packages/e1/68/66f1edfa9760213e9a85cf70a6c78a9db1a9d9bf0a36c7fdf9ed117bf163/zstandard-0.22.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d67d0d53d2a138f9e29d8acdabe11310c185e36f0a848efa104d4e40b808e4", size = 4845899 }, + { url = "https://files.pythonhosted.org/packages/cb/c5/d5f4521c5444f3d1e8bd0dc32b40766b0de1950eee46c734a3a98ddc8f96/zstandard-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:39b2853efc9403927f9065cc48c9980649462acbdf81cd4f0cb773af2fd734bc", size = 4920875 }, + { url = "https://files.pythonhosted.org/packages/f9/7a/2702eb29c3851a04f42e63443420520b392e432bdb30cb21c11dac1f5eb3/zstandard-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8a1b2effa96a5f019e72874969394edd393e2fbd6414a8208fea363a22803b45", size = 5451783 }, + { url = "https://files.pythonhosted.org/packages/08/3e/4b78e8378dfdb25f51a1123ec4e44f98a490d58ccf51104a3a9c6f821eb1/zstandard-0.22.0-cp312-cp312-win32.whl", hash = "sha256:88c5b4b47a8a138338a07fc94e2ba3b1535f69247670abfe422de4e0b344aae2", size = 442885 }, + { url = "https://files.pythonhosted.org/packages/b6/91/15feaf0d389f7d696ed0fbd75b51c6cbc04e9b8b474292a3bb2b5157e093/zstandard-0.22.0-cp312-cp312-win_amd64.whl", hash = "sha256:de20a212ef3d00d609d0b22eb7cc798d5a69035e81839f549b538eff4105d01c", size = 511809 }, + { url = "https://files.pythonhosted.org/packages/09/6c/d8eec6fb8da1cccdd11e01698ff513815d1a5cdb6bba71fba519161e1f25/zstandard-0.22.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d75f693bb4e92c335e0645e8845e553cd09dc91616412d1d4650da835b5449df", size = 921026 }, + { url = "https://files.pythonhosted.org/packages/fd/d5/ab90d6c148ecf239ad0a318c9db213235f052de2a33fdee8dcbd088e5d1a/zstandard-0.22.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:36a47636c3de227cd765e25a21dc5dace00539b82ddd99ee36abae38178eff9e", size = 703358 }, + { url = "https://files.pythonhosted.org/packages/90/81/0e2082b0f6e62f3ac3f5c6f12f2150db9cedf0c8cbed9d350979fd157f76/zstandard-0.22.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68953dc84b244b053c0d5f137a21ae8287ecf51b20872eccf8eaac0302d3e3b0", size = 4919266 }, + { url = "https://files.pythonhosted.org/packages/ef/e7/1cce80b1abc3b2d07eeb0a41a179adb2a49aba8b3064518497664a3ba3ba/zstandard-0.22.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2612e9bb4977381184bb2463150336d0f7e014d6bb5d4a370f9a372d21916f69", size = 5433250 }, + { url = "https://files.pythonhosted.org/packages/ef/60/2474dc2811948c357d10844724d02eb0a59d5721a8118a07741368877de8/zstandard-0.22.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:23d2b3c2b8e7e5a6cb7922f7c27d73a9a615f0a5ab5d0e03dd533c477de23004", size = 4846789 }, + { url = "https://files.pythonhosted.org/packages/a6/a0/8f9f8c5d8f32b7c627934f620f6a67c271861992781927e6ca76b4cdc0a9/zstandard-0.22.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:1d43501f5f31e22baf822720d82b5547f8a08f5386a883b32584a185675c8fbf", size = 4924703 }, + { url = "https://files.pythonhosted.org/packages/a9/d0/fe5da22515b96eb5dc46a67d74941932bb1ec1404bf403d1513efcad62b9/zstandard-0.22.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a493d470183ee620a3df1e6e55b3e4de8143c0ba1b16f3ded83208ea8ddfd91d", size = 5448797 }, + { url = "https://files.pythonhosted.org/packages/eb/af/09bccbeed3fa5e6d3b3da914530d6c9756a82d3363a7e92dc35c263b38af/zstandard-0.22.0-cp38-cp38-win32.whl", hash = "sha256:7034d381789f45576ec3f1fa0e15d741828146439228dc3f7c59856c5bcd3292", size = 442608 }, + { url = "https://files.pythonhosted.org/packages/38/54/e07cc78b8be4d305a74a515c4aee6d20516b1b158d2f26bbcd47da6bb42d/zstandard-0.22.0-cp38-cp38-win_amd64.whl", hash = "sha256:d8fff0f0c1d8bc5d866762ae95bd99d53282337af1be9dc0d88506b340e74b73", size = 511739 }, + { url = "https://files.pythonhosted.org/packages/a3/44/846dd0d14d863c294e94ddb3bb18fc6faa5e32b553ad6b201b55e6b85b7d/zstandard-0.22.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2fdd53b806786bd6112d97c1f1e7841e5e4daa06810ab4b284026a1a0e484c0b", size = 920932 }, + { url = "https://files.pythonhosted.org/packages/d9/15/7d40ac656fec0710394278e91649bdeea5bec0230fb18dd655f67e7b02e3/zstandard-0.22.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:73a1d6bd01961e9fd447162e137ed949c01bdb830dfca487c4a14e9742dccc93", size = 703344 }, + { url = "https://files.pythonhosted.org/packages/d4/f9/2b76671d8fbee77ba18b96f5da3b187bf7bbbce1bdcad59f1bb94a54a2b4/zstandard-0.22.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9501f36fac6b875c124243a379267d879262480bf85b1dbda61f5ad4d01b75a3", size = 4913505 }, + { url = "https://files.pythonhosted.org/packages/85/96/61a79e9e9c9e14e5e1baf84fd71115944320bac525fcd754695ba84e2084/zstandard-0.22.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48f260e4c7294ef275744210a4010f116048e0c95857befb7462e033f09442fe", size = 5429686 }, + { url = "https://files.pythonhosted.org/packages/19/16/845cd410ad0951a081b94398074daad70d4330c59f5853fb224187909f64/zstandard-0.22.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959665072bd60f45c5b6b5d711f15bdefc9849dd5da9fb6c873e35f5d34d8cfb", size = 4843367 }, + { url = "https://files.pythonhosted.org/packages/80/76/23caa1fa9de6f59826d0f45085f5d02c84bb98e0073977a5f90ec2b0b2f3/zstandard-0.22.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d22fdef58976457c65e2796e6730a3ea4a254f3ba83777ecfc8592ff8d77d303", size = 4920166 }, + { url = "https://files.pythonhosted.org/packages/ea/76/6878c4e54ed1fc2ed2f541ce3cbccacc5dc61fd2e7ae3dfcd2789b6fd6d5/zstandard-0.22.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a7ccf5825fd71d4542c8ab28d4d482aace885f5ebe4b40faaa290eed8e095a4c", size = 5443926 }, + { url = "https://files.pythonhosted.org/packages/56/45/48005b3ef457b8339c22ac0a4f6a02045787ef1b816d40708b78fee88fc7/zstandard-0.22.0-cp39-cp39-win32.whl", hash = "sha256:f058a77ef0ece4e210bb0450e68408d4223f728b109764676e1a13537d056bb0", size = 442619 }, + { url = "https://files.pythonhosted.org/packages/9f/46/911443d9d91749d27b355e2eb2b7aace6f01dca668cf602fd1669be6941a/zstandard-0.22.0-cp39-cp39-win_amd64.whl", hash = "sha256:e9e9d4e2e336c529d4c435baad846a181e39a982f823f7e4495ec0b0ec8538d2", size = 511727 }, +] diff --git a/e2e/bzlmod/uv/BUILD.bazel b/e2e/bzlmod/uv/BUILD.bazel new file mode 100644 index 0000000..5b5a56d --- /dev/null +++ b/e2e/bzlmod/uv/BUILD.bazel @@ -0,0 +1,103 @@ +load("@bazel_skylib//rules:write_file.bzl", "write_file") +load("@rules_pycross//pycross:defs.bzl", "pycross_wheel_build") +load("@rules_python//python:defs.bzl", "py_test") +load("@uv//:requirements.bzl", "all_requirements", "all_whl_requirements", "requirement") + +package(default_visibility = ["//visibility:public"]) + +pycross_wheel_build( + name = "zstandard_build", + config_settings = { + "--build-option": [ + "--no-cffi-backend", + "--system-zstd", + ], + }, + copts = ["-Wl,-s"], + native_deps = [ + "//third_party/zstd", + ], + post_build_hooks = [ + "@rules_pycross//pycross/hooks:repair_wheel", + ], + sdist = "@uv//zstandard:sdist", + tags = ["manual"], + deps = [ + "@uv//:setuptools", + "@uv//:wheel", + ], +) + +write_file( + name = "ipython_py", + out = "ipython.py", + content = [ + "import os", + "import tempfile", + "from IPython import start_ipython", + "with tempfile.TemporaryDirectory() as d:", + " os.environ['IPYTHONDIR'] = str(d)", + " start_ipython()", + ], +) + +# Tests + +py_test( + name = "test_library_usage_via_ipython", + srcs = [ + "ipython.py", + "//:test_zstandard.py", + ], + args = ["$(location //:test_zstandard.py)"], + main = "ipython.py", + deps = [ + "@uv//:ipython", + "@uv//:zstandard", + ], +) + +py_test( + name = "test_zstandard", + srcs = ["//:test_zstandard.py"], + deps = ["@uv//:zstandard"], +) + +py_test( + name = "test_regex", + srcs = ["//:test_regex.py"], + deps = ["@uv//:regex"], +) + +py_test( + name = "test_cowsay", + srcs = ["//:test_cowsay.py"], + main = "test_cowsay.py", + deps = ["@uv//:cowsay"], +) + +# Test using the `requirement` function +py_test( + name = "test_regex_using_requirement", + srcs = ["//:test_regex.py"], + main = "test_regex.py", + deps = [requirement("regex")], +) + +# Test using `all_requirements` +py_test( + name = "test_regex_using_all_requirements", + srcs = ["//:test_regex.py"], + main = "test_regex.py", + deps = all_requirements, +) + +# Test using `all_whl_requirements` +py_test( + name = "test_all_whl_requirements", + srcs = ["//:test_all_whl_requirements.py"], + env = { + "ALL_WHL_REQUIREMENTS": ",".join(all_whl_requirements), + }, + main = "test_all_whl_requirements.py", +) diff --git a/pycross/BUILD.bazel b/pycross/BUILD.bazel index f475122..4e24f9b 100644 --- a/pycross/BUILD.bazel +++ b/pycross/BUILD.bazel @@ -50,6 +50,7 @@ bzl_library( "//pycross/private:pdm_lock_model", "//pycross/private:poetry_lock_model", "//pycross/private:toolchain_helpers", + "//pycross/private:uv_lock_model", ], ) diff --git a/pycross/private/BUILD.bazel b/pycross/private/BUILD.bazel index dee9eb3..e7b2fbd 100644 --- a/pycross/private/BUILD.bazel +++ b/pycross/private/BUILD.bazel @@ -54,6 +54,12 @@ bzl_library( deps = [":internal_repo"], ) +bzl_library( + name = "uv_lock_model", + srcs = ["uv_lock_model.bzl"], + deps = [":internal_repo"], +) + bzl_library( name = "lock_repo", srcs = ["lock_repo.bzl"], diff --git a/pycross/private/bzlmod/BUILD.bazel b/pycross/private/bzlmod/BUILD.bazel index dda1515..a6b3aed 100644 --- a/pycross/private/bzlmod/BUILD.bazel +++ b/pycross/private/bzlmod/BUILD.bazel @@ -35,6 +35,7 @@ bzl_library( "//pycross/private:poetry_lock_model", "//pycross/private:pypi_file", "//pycross/private:resolved_lock_repo", + "//pycross/private:uv_lock_model", "@bazel_features//:features", ] + REPO_HTTP_DEPS, ) diff --git a/pycross/private/bzlmod/lock_import.bzl b/pycross/private/bzlmod/lock_import.bzl index d79dc8f..fdff73d 100644 --- a/pycross/private/bzlmod/lock_import.bzl +++ b/pycross/private/bzlmod/lock_import.bzl @@ -5,8 +5,9 @@ load("//pycross/private:lock_attrs.bzl", "package_annotation") load("//pycross/private:pdm_lock_model.bzl", "lock_repo_model_pdm") load("//pycross/private:poetry_lock_model.bzl", "lock_repo_model_poetry") load("//pycross/private:resolved_lock_repo.bzl", "resolved_lock_repo") +load("//pycross/private:uv_lock_model.bzl", "lock_repo_model_uv") load(":lock_hub_repo.bzl", "lock_hub_repo") -load(":tag_attrs.bzl", "COMMON_ATTRS", "COMMON_IMPORT_ATTRS", "PACKAGE_ATTRS", "PDM_IMPORT_ATTRS", "POETRY_IMPORT_ATTRS") +load(":tag_attrs.bzl", "COMMON_ATTRS", "COMMON_IMPORT_ATTRS", "PACKAGE_ATTRS", "PDM_IMPORT_ATTRS", "POETRY_IMPORT_ATTRS", "UV_IMPORT_ATTRS") def _generate_resolved_lock_repo(lock_info, serialized_lock_model): repo_name = lock_info.repo_name @@ -100,7 +101,7 @@ def _lock_import_impl(module_ctx): # A first pass initialize lock structures and make sure none of the repo names are duplicated. for module in module_ctx.modules: - for tag in module.tags.import_pdm + module.tags.import_poetry: + for tag in module.tags.import_pdm + module.tags.import_poetry + module.tags.import_uv: _check_unique_lock_repo(lock_owners, module, tag) lock_repos[tag.repo] = _lock_struct(module_ctx, tag) @@ -110,6 +111,8 @@ def _lock_import_impl(module_ctx): lock_model_structs[tag.repo] = lock_repo_model_pdm(**{attr: getattr(tag, attr) for attr in PDM_IMPORT_ATTRS}) for tag in module.tags.import_poetry: lock_model_structs[tag.repo] = lock_repo_model_poetry(**{attr: getattr(tag, attr) for attr in POETRY_IMPORT_ATTRS}) + for tag in module.tags.import_uv: + lock_model_structs[tag.repo] = lock_repo_model_uv(**{attr: getattr(tag, attr) for attr in UV_IMPORT_ATTRS}) # Add package attributes for module in module_ctx.modules: @@ -142,6 +145,10 @@ _import_poetry_tag = tag_class( doc = "Import a Poetry lock file.", attrs = POETRY_IMPORT_ATTRS | COMMON_IMPORT_ATTRS | COMMON_ATTRS, ) +_import_uv_tag = tag_class( + doc = "Import a uv lock file.", + attrs = UV_IMPORT_ATTRS | COMMON_IMPORT_ATTRS | COMMON_ATTRS, +) _package_tag = tag_class( doc = "Specify package-specific settings.", attrs = PACKAGE_ATTRS | COMMON_ATTRS, @@ -152,6 +159,7 @@ lock_import = module_extension( tag_classes = dict( import_pdm = _import_pdm_tag, import_poetry = _import_poetry_tag, + import_uv = _import_uv_tag, package = _package_tag, ), ) diff --git a/pycross/private/bzlmod/tag_attrs.bzl b/pycross/private/bzlmod/tag_attrs.bzl index d1ba9a3..fdfa7ba 100644 --- a/pycross/private/bzlmod/tag_attrs.bzl +++ b/pycross/private/bzlmod/tag_attrs.bzl @@ -7,6 +7,7 @@ load( _PDM_IMPORT_ATTRS = "PDM_IMPORT_ATTRS", _POETRY_IMPORT_ATTRS = "POETRY_IMPORT_ATTRS", _REGISTER_TOOLCHAINS_ATTRS = "REGISTER_TOOLCHAINS_ATTRS", + _UV_IMPORT_ATTRS = "UV_IMPORT_ATTRS", ) # Attrs common to all tags @@ -63,5 +64,6 @@ PACKAGE_ATTRS = dict( CREATE_ENVIRONMENTS_ATTRS = _CREATE_ENVIRONMENTS_ATTRS CREATE_REPOS_ATTRS = _CREATE_REPOS_ATTRS PDM_IMPORT_ATTRS = _PDM_IMPORT_ATTRS +UV_IMPORT_ATTRS = _UV_IMPORT_ATTRS POETRY_IMPORT_ATTRS = _POETRY_IMPORT_ATTRS REGISTER_TOOLCHAINS_ATTRS = _REGISTER_TOOLCHAINS_ATTRS diff --git a/pycross/private/lock_attrs.bzl b/pycross/private/lock_attrs.bzl index 9776719..b8d2b95 100644 --- a/pycross/private/lock_attrs.bzl +++ b/pycross/private/lock_attrs.bzl @@ -92,9 +92,9 @@ RENDER_ATTRS = dict( ), ) | CREATE_REPOS_ATTRS -PDM_IMPORT_ATTRS = dict( +_IMPORT_ATTRS = dict( lock_file = attr.label( - doc = "The pdm.lock file.", + doc = "The lock file.", allow_single_file = True, mandatory = True, ), @@ -250,3 +250,6 @@ def package_annotation( ignore_dependencies = ignore_dependencies, install_exclude_globs = install_exclude_globs, )) + +PDM_IMPORT_ATTRS = _IMPORT_ATTRS +UV_IMPORT_ATTRS = _IMPORT_ATTRS diff --git a/pycross/private/resolved_lock_repo.bzl b/pycross/private/resolved_lock_repo.bzl index c94b6b6..2a51277 100644 --- a/pycross/private/resolved_lock_repo.bzl +++ b/pycross/private/resolved_lock_repo.bzl @@ -11,6 +11,7 @@ load(":internal_repo.bzl", "exec_internal_tool") load(":lock_attrs.bzl", "RESOLVE_ATTRS", "handle_resolve_attrs") load(":pdm_lock_model.bzl", "repo_create_pdm_model", PDM_TRANSLATOR_TOOL = "TRANSLATOR_TOOL") load(":poetry_lock_model.bzl", "repo_create_poetry_model", POETRY_TRANSLATOR_TOOL = "TRANSLATOR_TOOL") +load(":uv_lock_model.bzl", "repo_create_uv_model", UV_TRANSLATOR_TOOL = "TRANSLATOR_TOOL") _RESOLVER_TOOL = Label("//pycross/private/tools:raw_lock_resolver.py") @@ -29,6 +30,8 @@ def _generate_lock_model_file(rctx): repo_create_pdm_model(rctx, model_params, "raw_lock.json") elif model_params["model_type"] == "poetry": repo_create_poetry_model(rctx, model_params, "raw_lock.json") + elif model_params["model_type"] == "uv": + repo_create_uv_model(rctx, model_params, "raw_lock.json") else: fail("Invalid model type: " + model_params["model_type"]) @@ -72,6 +75,7 @@ resolved_lock_repo = repository_rule( _RESOLVER_TOOL, PDM_TRANSLATOR_TOOL, POETRY_TRANSLATOR_TOOL, + UV_TRANSLATOR_TOOL, ]), ) | RESOLVE_ATTRS, ) diff --git a/pycross/private/tools/BUILD.bazel b/pycross/private/tools/BUILD.bazel index fbb8dbb..d8b777a 100644 --- a/pycross/private/tools/BUILD.bazel +++ b/pycross/private/tools/BUILD.bazel @@ -113,6 +113,18 @@ py_binary( ], ) +py_binary( + name = "uv_translator", + srcs = ["uv_translator.py"], + imports = ["../../.."], + visibility = ["//visibility:public"], + deps = [ + ":args", + ":lock_model", + "@rules_pycross_internal//deps:tomli", + ], +) + py_binary( name = "poetry_translator", srcs = ["poetry_translator.py"], diff --git a/pycross/private/tools/uv_translator.py b/pycross/private/tools/uv_translator.py new file mode 100644 index 0000000..9e22123 --- /dev/null +++ b/pycross/private/tools/uv_translator.py @@ -0,0 +1,454 @@ +from __future__ import annotations + +import os +import re +from collections import defaultdict +from collections.abc import Callable +from dataclasses import dataclass +from pathlib import Path +from typing import Any +from typing import Dict +from typing import List +from typing import Set +from urllib.parse import unquote +from urllib.parse import urlparse + +import tomli +from packaging.requirements import Requirement +from packaging.specifiers import SpecifierSet +from packaging.utils import NormalizedName +from packaging.version import Version + +from pycross.private.tools.args import FlagFileArgumentParser +from pycross.private.tools.lock_model import package_canonical_name +from pycross.private.tools.lock_model import PackageDependency +from pycross.private.tools.lock_model import PackageFile +from pycross.private.tools.lock_model import PackageKey +from pycross.private.tools.lock_model import RawLockSet +from pycross.private.tools.lock_model import RawPackage + +EDITABLE_PATTERN = re.compile("^ *-e +") + + +class LockfileIncompatibleException(Exception): + pass + + +class LockfileNotStaticException(Exception): + pass + + +class MismatchedVersionException(Exception): + pass + + +def get_default_dependencies(lock: Dict[str, Any]) -> List[Requirement]: + deps = lock.get("project", {}).get("dependencies", []) + return [Requirement(dep) for dep in deps] + + +def get_optional_dependencies(lock: Dict[str, Any]) -> Dict[str, List[Requirement]]: + dep_groups = lock.get("project", {}).get("optional-dependencies", {}) + return {group: [Requirement(dep) for dep in deps] for group, deps in dep_groups.items()} + + +def get_development_dependencies(lock: Dict[str, Any]) -> Dict[str, List[Requirement]]: + dep_groups = lock.get("tool", {}).get("uv", {}).get("dev-dependencies", {}) + return {group: [Requirement(EDITABLE_PATTERN.sub("", dep)) for dep in deps] for group, deps in dep_groups.items()} + + +def _print_warn(msg): + print("WARNING:", msg) + + +@dataclass +class Package: + name: NormalizedName + version: Version + python_versions: SpecifierSet + dependencies: Set[Requirement] + files: Set[PackageFile] + is_local: bool + resolved_dependencies: Set[PackageDependency] + extras: Set[str] + + def __post_init__(self): + self.extras = set(e.lower() for e in self.extras) + + @property + def key(self) -> PackageKey: + return PackageKey.from_parts(self.name, self.version) + + def satisfies(self, req: Requirement) -> bool: + # The left side is already canonicalized. + if self.name != package_canonical_name(req.name): + return False + # Extras are case-insensitive. The left side is already lower-cased. + if not self.extras.issuperset(set(r.lower() for r in req.extras)): + return False + return req.specifier.contains(self.version, prereleases=True) + + def to_lock_package(self) -> RawPackage: + assert not self.is_local, "Local packages have no analogue in pycross lockfile" + dependencies_without_self = sorted( + [dep for dep in self.resolved_dependencies if dep.key != self.key], key=lambda p: p.key + ) + return RawPackage( + name=self.name, + version=self.version, + python_versions=str(self.python_versions), + dependencies=dependencies_without_self, + files=sorted(self.files, key=lambda f: f.name), + ) + + def merge(self, other: Package) -> Package: + if (self.name, self.version) != (other.name, other.version): + raise ValueError(f"Can only merge packages with the same name and version, not {self.key} and {other.key}") + if self.python_versions != other.python_versions: + raise ValueError( + f"Can only merge packages that depend on the same Python version, not {self.python_versions} and {other.python_versions}" + ) + + merged_dependencies = set(self.dependencies) | set(other.dependencies) + merged_files = set(self.files) | set(other.files) + merged_is_local = self.is_local or other.is_local + merged_resolved_dependencies = set(self.resolved_dependencies) | set(other.resolved_dependencies) + merged_extras = set(self.extras) | set(other.extras) + + return Package( + name=self.name, + version=self.version, + python_versions=self.python_versions, + dependencies=merged_dependencies, + files=merged_files, + is_local=merged_is_local, + resolved_dependencies=merged_resolved_dependencies, + extras=merged_extras, + ) + + +def parse_file_info(file_info: Dict[str, Any]) -> PackageFile: + if "file" in file_info: + file_name = file_info["file"] + urls = tuple() + elif "url" in file_info: + url = file_info["url"] + _, file_name = urlparse(url).path.rsplit("/", 1) + file_name = unquote(file_name) + urls = (url,) + else: + raise AssertionError("file entry has no file or url member") + file_hash = file_info["hash"] + assert file_hash.startswith("sha256:") + return PackageFile(name=file_name, sha256=file_hash[7:], urls=urls) + + +# Dataclass to hold the project and lock files +@dataclass +class ProjectFiles: + project_file: dict + lock_file: dict + + +# Function to read the project and lock files + + +def read_files(project_file: Path, lock_file: Path) -> ProjectFiles: + try: + with open(project_file, "rb") as f: + project_dict = tomli.load(f) + except Exception as e: + raise Exception(f"Could not load project file: {project_file}: {e}") + + try: + with open(lock_file, "rb") as f: + lock_dict = tomli.load(f) + except Exception as e: + raise Exception(f"Could not load lock file: {lock_file}: {e}") + + return ProjectFiles(project_file=project_dict, lock_file=lock_dict) + + +def validate_uv_lockfile_version(lock_dict: Dict[str, Any]) -> None: + lock_version = lock_dict.get("version") + if not isinstance(lock_version, int): + raise LockfileIncompatibleException(f"Lock file version {lock_version} is not an integer") + if lock_version != 1: + raise LockfileIncompatibleException(f"Lock file version {lock_version} is not supported") + + +def translate( + project_dict: Dict[str, Any], + packages_list: list[Dict[str, Any]], + default_group: bool, + optional_groups: List[str], + all_optional_groups: bool, + development_groups: List[str], + all_development_groups: bool, + package_processor: Callable[[list[Dict[str, Any]]], Dict[PackageKey, Package]], +) -> RawLockSet: + requirements: List[Requirement] = [] + + default_dependencies = get_default_dependencies(project_dict) + optional_dependencies = get_optional_dependencies(project_dict) + development_dependencies = get_development_dependencies(project_dict) + + if default_group: + requirements.extend(default_dependencies) + + if all_optional_groups: + optional_groups = list(optional_dependencies) + + if all_development_groups: + development_groups = list(development_dependencies) + + for group_name in optional_groups: + if group_name not in optional_dependencies: + raise Exception(f"Non-existent optional dependency group: {group_name}") + requirements.extend(optional_dependencies[group_name]) + + for group_name in development_groups: + if group_name not in development_dependencies: + raise Exception(f"Non-existent development dependency group: {group_name}") + requirements.extend(development_dependencies[group_name]) + + pinned_package_specs: Dict[NormalizedName, Requirement] = {} + for req in requirements: + pin = package_canonical_name(req.name) + pinned_package_specs[pin] = req + + distinct_packages = package_processor(packages_list) + all_packages = distinct_packages.values() + + # Next, group packages by their canonical name + packages_by_canonical_name: Dict[str, List[Package]] = defaultdict(list) + for package in all_packages: + packages_by_canonical_name[package.name].append(package) + + # And sort the packages by version in descending order (newest first) + for package_list in packages_by_canonical_name.values(): + package_list.sort(key=lambda p: p.version, reverse=True) + + # Next, iterate through each package's dependencies and find the newest one that matches. + # Construct a PackageDependency and store it. + for package in all_packages: + for dep in package.dependencies: + dependency_packages = packages_by_canonical_name[package_canonical_name(dep.name)] + for dep_pkg in dependency_packages: + if dep_pkg.satisfies(dep): + resolved = PackageDependency( + name=dep_pkg.name, + version=dep_pkg.version, + marker=str(dep.marker or ""), + ) + package.resolved_dependencies.add(resolved) + break + else: + raise MismatchedVersionException( + f"Found no packages to satisfy dependency (name={dep.name}, spec={dep.specifier})" + ) + + pinned_keys: Dict[NormalizedName, PackageKey] = {} + + for pin, pin_spec in pinned_package_specs.items(): + pin_packages = packages_by_canonical_name[pin] + for pin_pkg in pin_packages: + if pin_spec.specifier.contains(pin_pkg.version, prereleases=True): + pinned_keys[pin] = pin_pkg.key + break + else: + raise MismatchedVersionException(f"Found no packages to satisfy pin (name={pin}, spec={pin_spec})") + + # Replace pins of local packages with pins of their dependencies. + # We may need to loop multiple times if local packages depend on one another. + while local_pins := [key for key in pinned_keys.values() if distinct_packages[key].is_local]: + for pin_key in local_pins: + pin_pkg = distinct_packages[pin_key] + pinned_keys.update({dep.name: dep.key for dep in pin_pkg.resolved_dependencies}) + del pinned_keys[pin_key.name] + + lock_packages: Dict[PackageKey, RawPackage] = {} + for package in all_packages: + if package.is_local: + _print_warn( + "Local package {} elided from pycross repo. It can still be referenced directly from the main repo.".format( + package.key + ) + ) + continue + lock_package = package.to_lock_package() + lock_packages[lock_package.key] = lock_package + + return RawLockSet( + packages=lock_packages, + pins=pinned_keys, + ) + + +def parse_flags() -> Any: + parser = FlagFileArgumentParser(description="Generate pycross dependency bzl file.") + + parser.add_argument( + "--project-file", + type=Path, + required=True, + help="The path to pyproject.toml.", + ) + + parser.add_argument( + "--lock-file", + type=Path, + required=True, + help="The path to uv.lock.", + ) + + parser.add_argument( + "--default-group", + action="store_true", + help="Whether to install dependencies from the default group.", + ) + + parser.add_argument( + "--optional-group", + action="append", + default=[], + help="Optional dependency groups to install.", + ) + + parser.add_argument( + "--all-optional-groups", + action="store_true", + help="Install all optional dependency groups.", + ) + + parser.add_argument( + "--development-group", + action="append", + default=[], + help="Development dependency groups to install.", + ) + + parser.add_argument( + "--all-development-groups", + action="store_true", + help="Install all development dependency groups.", + ) + + parser.add_argument( + "--require-static-urls", + action="store_true", + help="Require that the lock file provide static URLs.", + ) + + parser.add_argument( + "--output", + type=Path, + required=True, + help="The path to the output bzl file.", + ) + + return parser.parse_args() + + +def collect_and_process_packages(packages_list: list[Dict[str, Any]]) -> Dict[PackageKey, Package]: + distinct_packages: Dict[PackageKey, Package] = {} + # Pull out all Package entries in a uv-specific model. + for lock_pkg in packages_list: + package_listed_name = lock_pkg["name"] + package_name = package_canonical_name(package_listed_name) + package_version = lock_pkg["version"] + package_requires_python = lock_pkg.get("requires_python", "") + package_extras = lock_pkg.get("extras", []) + + if package_requires_python == "*": + # Special case for all python versions + package_requires_python = "" + + optional_deps = [] + for dep in lock_pkg.get("optional-dependencies", {}).values(): + optional_deps.extend(dep) + dependencies = set() + for dep in lock_pkg.get("dependencies", []) + optional_deps: + name = dep.get("name") + version = dep.get("version") + marker = dep.get("marker") + if version: + dep_string = f"{name}=={version}" + else: + dep_string = name + if marker: + dep_string += f";{marker}" + + dependencies.add(Requirement(dep_string)) + + files = lock_pkg.get("wheels", []) + if lock_pkg.get("sdist"): + files.append(lock_pkg.get("sdist")) + + files = {parse_file_info(f) for f in files} + + is_local = lock_pkg.get("source") == {"editable": "."} or lock_pkg.get("sdist") == {"path": "."} + + if not files and not is_local: + raise Exception(lock_pkg, is_local) + + package = Package( + name=package_name, + version=Version(package_version), + python_versions=SpecifierSet(package_requires_python), + dependencies=dependencies, + files=files, + is_local=is_local, + resolved_dependencies=set(), + extras=set(package_extras), + ) + if package.key in distinct_packages: + distinct_packages[package.key] = package.merge(distinct_packages[package.key]) + else: + distinct_packages[package.key] = package + return distinct_packages + + +def validate_lockfile_version(lock_dict: Dict[str, Any]) -> None: + lock_version = lock_dict.get("version") + if not isinstance(lock_version, int): + raise LockfileIncompatibleException(f"Lock file version {lock_version} is not an integer") + if lock_version != 1: + raise LockfileIncompatibleException(f"Lock file version {lock_version} is not supported") + + +def main(args: Any) -> None: + """Entry point for the uv_translator script.""" + + output = args.output + + project_files = read_files(args.project_file, args.lock_file) + + project_dict = project_files.project_file + lock_dict = project_files.lock_file + + validate_lockfile_version(lock_dict) + + packages_list = lock_dict.get("distribution", []) + + lock_set = translate( + project_dict, + packages_list, + default_group=args.default_group, + optional_groups=args.optional_group, + all_optional_groups=args.all_optional_groups, + development_groups=args.development_group, + all_development_groups=args.all_development_groups, + package_processor=collect_and_process_packages, + ) + + with open(output, "w") as f: + f.write(lock_set.to_json(indent=2)) + + +if __name__ == "__main__": + # When under `bazel run`, change to the actual working dir. + if "BUILD_WORKING_DIRECTORY" in os.environ: + os.chdir(os.environ["BUILD_WORKING_DIRECTORY"]) + + main(parse_flags()) diff --git a/pycross/private/uv_lock_model.bzl b/pycross/private/uv_lock_model.bzl new file mode 100644 index 0000000..b46ac52 --- /dev/null +++ b/pycross/private/uv_lock_model.bzl @@ -0,0 +1,110 @@ +"""Implementation of the pycross_uv_lock_model rule.""" + +load(":internal_repo.bzl", "exec_internal_tool") +load(":lock_attrs.bzl", "UV_IMPORT_ATTRS") + +TRANSLATOR_TOOL = Label("//pycross/private/tools:uv_translator.py") + +def _handle_args(attrs, project_file, lock_file, output): + args = [] + args.extend(["--project-file", project_file]) + args.extend(["--lock-file", lock_file]) + args.extend(["--output", output]) + + if attrs.default: + args.append("--default") + + for group in attrs.optional_groups: + args.extend(["--optional-group", group]) + + if attrs.all_optional_groups: + args.append("--all-optional-groups") + + for group in attrs.development_groups: + args.extend(["--development-group", group]) + + if attrs.all_development_groups: + args.append("--all-development-groups") + + if attrs.require_static_urls: + args.append("--require-static-urls") + + return args + +def _pycross_uv_lock_model_impl(ctx): + out = ctx.actions.declare_file(ctx.attr.name + ".json") + + args = ctx.actions.args().use_param_file("--flagfile=%s") + args.add_all( + _handle_args( + ctx.attr, + ctx.file.project_file.path, + ctx.file.lock_file.path, + out.path, + ), + ) + + ctx.actions.run( + inputs = ( + ctx.files.project_file + + ctx.files.lock_file + ), + outputs = [out], + executable = ctx.executable._tool, + arguments = [args], + ) + + return [ + DefaultInfo( + files = depset([out]), + ), + ] + +pycross_uv_lock_model = rule( + implementation = _pycross_uv_lock_model_impl, + attrs = { + "_tool": attr.label( + default = Label("//pycross/private/tools:uv_translator"), + cfg = "exec", + executable = True, + ), + } | UV_IMPORT_ATTRS, +) + +def lock_repo_model_uv(*, project_file, lock_file, default = True, optional_groups = [], all_optional_groups = False, development_groups = [], all_development_groups = False, require_static_urls = True): + return json.encode(dict( + model_type = "uv", + project_file = str(project_file), + lock_file = str(lock_file), + default = default, + optional_groups = optional_groups, + all_optional_groups = all_optional_groups, + development_groups = development_groups, + all_development_groups = all_development_groups, + require_static_urls = require_static_urls, + )) + +def repo_create_uv_model(rctx, params, output): + """Run the uv lock translator. + + Args: + rctx: The repository_ctx or module_ctx object. + params: a struct or dict containing the same attrs as the pycross_uv_lock_model rule. + output: the output file. + """ + if type(params) == "dict": + attrs = struct(**params) + else: + attrs = params + args = _handle_args( + attrs, + str(rctx.path(Label(attrs.project_file))), + str(rctx.path(Label(attrs.lock_file))), + output, + ) + + exec_internal_tool( + rctx, + TRANSLATOR_TOOL, + args, + ) diff --git a/pycross/workspace.bzl b/pycross/workspace.bzl index 2d7ec49..aaa3e16 100644 --- a/pycross/workspace.bzl +++ b/pycross/workspace.bzl @@ -11,8 +11,13 @@ load( _lock_repo_model_poetry = "lock_repo_model_poetry", ) load("//pycross/private:toolchain_helpers.bzl", _pycross_register_for_python_toolchains = "pycross_register_for_python_toolchains") +load( + "//pycross/private:uv_lock_model.bzl", + _lock_repo_model_uv = "lock_repo_model_uv", +) lock_repo_model_pdm = _lock_repo_model_pdm +lock_repo_model_uv = _lock_repo_model_uv lock_repo_model_poetry = _lock_repo_model_poetry pycross_lock_file_repo = _pycross_lock_file_repo pycross_lock_repo = _pycross_lock_repo