diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..9730b9a --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,77 @@ +name: "Sphinx: Render docs" + +on: + pull_request: + branches: + - "**" + paths: + # Run for changes to *this* workflow file, but not for other workflows + - ".github/workflows/docs.yml" + # Trigger off docs and Python source code changes + - "docs/**" + - "src/**.py" + push: + branches: + - main + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + # Not actually a matrix build, but defined as one for consistency + max-parallel: 1 + matrix: + python-version: [3.12] + os: [ubuntu-latest] + permissions: + # Allow updating the gh-pages branch + contents: write + + # Check https://github.com/actions/action-versions/tree/main/config/actions + # for latest versions if the standard actions start emitting warnings + steps: + - uses: actions/checkout@v4 + + # sphinx-action uses docker under the hood and doesn't play nice with the + # dependency caching, so it may be better to switch to using `tox -e docs` + # and living without the nice integrated GitHub Actions error reporting. + + # - name: Set up Python ${{ matrix.python-version }} + # uses: actions/setup-python@v5 + # with: + # python-version: ${{ matrix.python-version }} + + # - name: Get pip cache dir + # id: pip-cache + # run: | + # echo "dir=$(python -m pip cache dir)" >> $GITHUB_OUTPUT + + # - name: Cache docs build dependencies + # uses: actions/cache@v4 + # with: + # path: ${{ steps.pip-cache.outputs.dir }} + # key: + # pip-docs-${{ matrix.os }}-${{ matrix.python-version }}-v1-${{ hashFiles('docs/requirements.txt') }} + # restore-keys: | + # pip-docs-${{ matrix.os }}-${{ matrix.python-version }}-v1- + + - name: Build HTML + uses: ammaraskar/sphinx-action@8.0.2 + with: + docs-folder: "docs/" + # Skip link check until after the venvstacks repo is public + # pre-build-command: "sphinx-build -b linkcheck . _build" + build-command: "sphinx-build -b dirhtml . _build" + + - name: Upload artifacts + uses: actions/upload-artifact@v4 + with: + name: html-docs + path: docs/_build/ + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + if: github.ref == 'refs/heads/main' + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: docs/_build/ diff --git a/README.md b/README.md index eed1c5b..7f86e11 100644 --- a/README.md +++ b/README.md @@ -67,6 +67,8 @@ Caveats and Limitations declared as stable in the documentation may be renamed or relocated without a deprecation period. API stabilisation (mostly splitting up the overly large `venvstacks.stacks` namespace) will be the trigger for the 1.0 milestone release. +* while the `venvstacks` CLI is broadly stable, there are still some specific areas + where changes may occur (such as in the handling of relative paths). * dynamic library dependencies across layers currently only work on Windows. There is a [proposal](https://github.com/lmstudio-ai/venvstacks/issues/1) in place for resolving that limitation, but it has not yet been implemented. diff --git a/ci-bootstrap-requirements.txt b/ci-bootstrap-requirements.txt index 42a5616..e39e3a3 100644 --- a/ci-bootstrap-requirements.txt +++ b/ci-bootstrap-requirements.txt @@ -19,9 +19,9 @@ distlib==0.3.9 \ filelock==3.16.1 \ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 -findpython==0.6.1 \ - --hash=sha256:1fb4d709205de185b0561900267dfff64a841c910fe28d6038b2394ff925a81a \ - --hash=sha256:56e52b409a92bcbd495cf981c85acf137f3b3e51cc769b46eba219bb1ab7533c +findpython==0.6.2 \ + --hash=sha256:bda62477f858ea623ef2269f5e734469a018104a5f6c0fd9317ba238464ddb76 \ + --hash=sha256:e0c75ba9f35a7f9bb4423eb31bd17358cccf15761b6837317719177aeff46723 h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -69,9 +69,9 @@ packaging==24.1 \ pbs-installer==2024.10.10 \ --hash=sha256:228bba8e78134c407ee6637da6a5a16479aaa702332bfb1b95d873fc00802305 \ --hash=sha256:b82fb5c96a4ca2a8c2ea2521268fa83fa18c1bfa32decfb3d77139a07c13f90c -pdm==2.19.2 \ - --hash=sha256:42af4e0897b139656e003767e99c4f77014bf36d9a7b759d3e09b49ee5979143 \ - --hash=sha256:efb39264569181d0375536ef81c556648f16b540d429a53715730490a2283567 +pdm==2.19.3 \ + --hash=sha256:80594e5d6167fb17ea724df09b68cdfe9c601ad7f218f1beea2c032b61bf30e9 \ + --hash=sha256:a9cc7f2078cd3b25ac645ffb5eca9d6b3d5dfcd788eaddfb6083432da71c97c2 platformdirs==4.3.6 \ --hash=sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907 \ --hash=sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb @@ -111,6 +111,6 @@ typing-extensions==4.12.2 \ unearth==0.17.2 \ --hash=sha256:0b8a2afd3476f1ab6155fc579501ac47fffe43547d88a70e5a5b76a7fe6caa2c \ --hash=sha256:4d21af1238a583835fca156322f7225382e718cdcc42d6278050a88e605c4ad5 -virtualenv==20.26.6 \ - --hash=sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48 \ - --hash=sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2 +virtualenv==20.27.0 \ + --hash=sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2 \ + --hash=sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655 diff --git a/ci-constraints.txt b/ci-constraints.txt index 673a74e..6d3d61a 100644 --- a/ci-constraints.txt +++ b/ci-constraints.txt @@ -1,12 +1,21 @@ # This file is @generated by PDM. # Please do not edit it manually. +alabaster==1.0.0 \ + --hash=sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e \ + --hash=sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b anyio==4.6.2.post1 \ --hash=sha256:4c8bc31ccdb51c7f7bd251f51c609e038d63e34219b44aa86e47576389880b4c \ --hash=sha256:6d170c36fba3bdd840c73d3868c1e777e33676a69c3a72cf0a0d5d6d8009b61d attrs==24.2.0 \ --hash=sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346 \ --hash=sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2 +babel==2.16.0 \ + --hash=sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b \ + --hash=sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316 +beautifulsoup4==4.12.3 \ + --hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \ + --hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed blinker==1.8.2 \ --hash=sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01 \ --hash=sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83 @@ -22,6 +31,24 @@ certifi==2024.8.30 \ chardet==5.2.0 \ --hash=sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7 \ --hash=sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970 +charset-normalizer==3.4.0 \ + --hash=sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6 \ + --hash=sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c \ + --hash=sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e \ + --hash=sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc \ + --hash=sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc \ + --hash=sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db \ + --hash=sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee \ + --hash=sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b \ + --hash=sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15 \ + --hash=sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250 \ + --hash=sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9 \ + --hash=sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944 \ + --hash=sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27 \ + --hash=sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114 \ + --hash=sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf \ + --hash=sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed \ + --hash=sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079 click==8.1.7 \ --hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \ --hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de @@ -34,20 +61,18 @@ dep-logic==0.4.9 \ distlib==0.3.9 \ --hash=sha256:47f8c22fd27c27e25a65601af709b38e4f0a45ea4fc2e710f65755fa8caaaf87 \ --hash=sha256:a60f20dea646b8a33f3e7772f74dc0b2d0772d2837ee1342a00645c81edf9403 -dulwich==0.22.1 \ - --hash=sha256:12482e318895da9acabea7c0cc70b35d36833e7cb2def511ab3a63617f5c1af3 \ - --hash=sha256:6dc42afedc8cda4f2fd15a06d2e9e41281074a02cdf31bb2e0dde4d80766a408 \ - --hash=sha256:82f26e592e9a36ab33bcdb419c7d53320e26c85dfc254cdb84f5f561a2fcaabf \ - --hash=sha256:9d19f04ecd4628a0e4587b4c4e98e040b87924c1362ae5aa27420435f05d5dd8 \ - --hash=sha256:a18d1392eabd02f337dcba23d723a4dcca87274ce8693cf88e6320f38bc3fdcd \ - --hash=sha256:e36d85967cfbf25da1c7bc3d6921adc5baa976969d926aaf1582bd5fd7e94758 \ - --hash=sha256:e90b8a2f24149c5803b733a24f1a016a2943b1f5a9ab2360db545e4638354c35 +docutils==0.21.2 \ + --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \ + --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2 filelock==3.16.1 \ --hash=sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0 \ --hash=sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435 -findpython==0.6.1 \ - --hash=sha256:1fb4d709205de185b0561900267dfff64a841c910fe28d6038b2394ff925a81a \ - --hash=sha256:56e52b409a92bcbd495cf981c85acf137f3b3e51cc769b46eba219bb1ab7533c +findpython==0.6.2 \ + --hash=sha256:bda62477f858ea623ef2269f5e734469a018104a5f6c0fd9317ba238464ddb76 \ + --hash=sha256:e0c75ba9f35a7f9bb4423eb31bd17358cccf15761b6837317719177aeff46723 +furo==2024.8.6 \ + --hash=sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c \ + --hash=sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01 h11==0.14.0 \ --hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \ --hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761 @@ -63,15 +88,39 @@ httpx==0.27.2 \ idna==3.10 \ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3 +imagesize==1.4.1 \ + --hash=sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b \ + --hash=sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a iniconfig==2.0.0 \ --hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \ --hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374 installer==0.7.0 \ --hash=sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53 \ --hash=sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631 +jinja2==3.1.4 \ + --hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \ + --hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d markdown-it-py==3.0.0 \ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb +markupsafe==3.0.2 \ + --hash=sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396 \ + --hash=sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b \ + --hash=sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225 \ + --hash=sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87 \ + --hash=sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d \ + --hash=sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93 \ + --hash=sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf \ + --hash=sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84 \ + --hash=sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb \ + --hash=sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c \ + --hash=sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd \ + --hash=sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d \ + --hash=sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8 \ + --hash=sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f \ + --hash=sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f \ + --hash=sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0 \ + --hash=sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430 mdurl==0.1.2 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba @@ -92,24 +141,24 @@ msgpack==1.1.0 \ --hash=sha256:d46cf9e3705ea9485687aa4001a76e44748b609d260af21c4ceea7f2212a501d \ --hash=sha256:dd432ccc2c72b914e4cb77afce64aab761c1137cc698be3984eee260bcb2896e \ --hash=sha256:fd2906780f25c8ed5d7b323379f6138524ba793428db5d0e9d226d3fa6aa1788 -mypy==1.12.0 \ - --hash=sha256:1ebf9e796521f99d61864ed89d1fb2926d9ab6a5fab421e457cd9c7e4dd65aa9 \ - --hash=sha256:20c7c5ce0c1be0b0aea628374e6cf68b420bcc772d85c3c974f675b88e3e6e57 \ - --hash=sha256:233e11b3f73ee1f10efada2e6da0f555b2f3a5316e9d8a4a1224acc10e7181d3 \ - --hash=sha256:2f106db5ccb60681b622ac768455743ee0e6a857724d648c9629a9bd2ac3f721 \ - --hash=sha256:48d3e37dd7d9403e38fa86c46191de72705166d40b8c9f91a3de77350daa0893 \ - --hash=sha256:4ae8959c21abcf9d73aa6c74a313c45c0b5a188752bf37dace564e29f06e9c1b \ - --hash=sha256:4b86de37a0da945f6d48cf110d5206c5ed514b1ca2614d7ad652d4bf099c7de7 \ - --hash=sha256:52b9e1492e47e1790360a43755fa04101a7ac72287b1a53ce817f35899ba0521 \ - --hash=sha256:5bc81701d52cc8767005fdd2a08c19980de9ec61a25dbd2a937dfb1338a826f9 \ - --hash=sha256:65a22d87e757ccd95cbbf6f7e181e6caa87128255eb2b6be901bb71b26d8a99d \ - --hash=sha256:8462655b6694feb1c99e433ea905d46c478041a8b8f0c33f1dab00ae881b2164 \ - --hash=sha256:923ea66d282d8af9e0f9c21ffc6653643abb95b658c3a8a32dca1eff09c06475 \ - --hash=sha256:a64ee25f05fc2d3d8474985c58042b6759100a475f8237da1f4faf7fcd7e6309 \ - --hash=sha256:c72861b7139a4f738344faa0e150834467521a3fba42dc98264e5aa9507dd601 \ - --hash=sha256:e478601cc3e3fa9d6734d255a59c7a2e5c2934da4378f3dd1e3411ea8a248642 \ - --hash=sha256:faca7ab947c9f457a08dcb8d9a8664fd438080e002b0fa3e41b0535335edcf7f \ - --hash=sha256:fd313226af375d52e1e36c383f39bf3836e1f192801116b31b090dfcd3ec5266 +mypy==1.12.1 \ + --hash=sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66 \ + --hash=sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735 \ + --hash=sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931 \ + --hash=sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a \ + --hash=sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02 \ + --hash=sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0 \ + --hash=sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635 \ + --hash=sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179 \ + --hash=sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81 \ + --hash=sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811 \ + --hash=sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042 \ + --hash=sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f \ + --hash=sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6 \ + --hash=sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e \ + --hash=sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc \ + --hash=sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4 \ + --hash=sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d mypy-extensions==1.0.0 \ --hash=sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d \ --hash=sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782 @@ -119,9 +168,9 @@ packaging==24.1 \ pbs-installer==2024.10.10 \ --hash=sha256:228bba8e78134c407ee6637da6a5a16479aaa702332bfb1b95d873fc00802305 \ --hash=sha256:b82fb5c96a4ca2a8c2ea2521268fa83fa18c1bfa32decfb3d77139a07c13f90c -pdm==2.19.2 \ - --hash=sha256:42af4e0897b139656e003767e99c4f77014bf36d9a7b759d3e09b49ee5979143 \ - --hash=sha256:efb39264569181d0375536ef81c556648f16b540d429a53715730490a2283567 +pdm==2.19.3 \ + --hash=sha256:80594e5d6167fb17ea724df09b68cdfe9c601ad7f218f1beea2c032b61bf30e9 \ + --hash=sha256:a9cc7f2078cd3b25ac645ffb5eca9d6b3d5dfcd788eaddfb6083432da71c97c2 pip==24.2 \ --hash=sha256:2cd581cf58ab7fcfca4ce8efa6dcacd0de5bf8d0a3eb9ec927e07405f4d9e2a2 \ --hash=sha256:5b5e490b5e9cb275c879595064adce9ebd31b854e3e803740b72f9ccf34a45b8 @@ -152,37 +201,70 @@ pytest-subtests==0.13.1 \ python-dotenv==1.0.1 \ --hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \ --hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a +requests==2.32.3 \ + --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \ + --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6 resolvelib==1.0.1 \ --hash=sha256:04ce76cbd63fded2078ce224785da6ecd42b9564b1390793f64ddecbe997b309 \ --hash=sha256:d2da45d1a8dfee81bdd591647783e340ef3bcb104b54c383f70d422ef5cc7dbf rich==13.9.2 \ --hash=sha256:51a2c62057461aaf7152b4d611168f93a9fc73068f8ded2790f29fe2b5366d0c \ --hash=sha256:8c82a3d3f8dcfe9e734771313e606b39d8247bb6b826e196f4914b333b743cf1 -ruff==0.6.9 \ - --hash=sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec \ - --hash=sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c \ - --hash=sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117 \ - --hash=sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa \ - --hash=sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93 \ - --hash=sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2 -setuptools==75.1.0 \ - --hash=sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2 \ - --hash=sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538 +ruff==0.7.0 \ + --hash=sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e \ + --hash=sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06 \ + --hash=sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b \ + --hash=sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737 \ + --hash=sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9 \ + --hash=sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2 +setuptools==75.2.0 \ + --hash=sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec \ + --hash=sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8 shellingham==1.5.4 \ --hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \ --hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de sniffio==1.3.1 \ --hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \ --hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc +snowballstemmer==2.2.0 \ + --hash=sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1 \ + --hash=sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a socksio==1.0.0 \ --hash=sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3 \ --hash=sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac +soupsieve==2.6 \ + --hash=sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb \ + --hash=sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9 +sphinx==8.1.3 \ + --hash=sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2 \ + --hash=sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927 +sphinx-basic-ng==1.0.0b2 \ + --hash=sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9 \ + --hash=sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b +sphinxcontrib-applehelp==2.0.0 \ + --hash=sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1 \ + --hash=sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5 +sphinxcontrib-devhelp==2.0.0 \ + --hash=sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad \ + --hash=sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2 +sphinxcontrib-htmlhelp==2.1.0 \ + --hash=sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8 \ + --hash=sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9 +sphinxcontrib-jsmath==1.0.1 \ + --hash=sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178 \ + --hash=sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8 +sphinxcontrib-qthelp==2.0.0 \ + --hash=sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab \ + --hash=sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb +sphinxcontrib-serializinghtml==2.0.0 \ + --hash=sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331 \ + --hash=sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d tomlkit==0.13.2 \ --hash=sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde \ --hash=sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79 -tox==4.21.2 \ - --hash=sha256:13d996adcd792e7c82994b0e116d85efd84f0c6d185254d83d156f73f86b2038 \ - --hash=sha256:49381ff102296753e378fa5ff30e42a35e695f149b4dbf8a2c49d15fdb5797b2 +tox==4.23.0 \ + --hash=sha256:46da40afb660e46238c251280eb910bdaf00b390c7557c8e4bb611f422e9db12 \ + --hash=sha256:a6bd7d54231d755348d3c3a7b450b5bf6563833716d1299a1619587a1b77a3bf tox-gh==1.4.4 \ --hash=sha256:4ea585f66585b90f5826b1677cfc9453747792a0f9ff83d468603bc17556e07b \ --hash=sha256:b962e0f8c4619e98d11c2a135939876691e148b843b7dac4cff7de1dc4f7c215 @@ -211,9 +293,9 @@ uv==0.4.21 \ --hash=sha256:9dcddbb3b6e1662c6db41d63db539742450e2ce17d6c746329c016e3651bfb4a \ --hash=sha256:a1a9a126ce48f0f0893891adb5a9749220425169092f3e4da1216168736ac16d \ --hash=sha256:ba3e3b40cc1d5a980d36589775d6a7e4defa1b33e7e06423af0e395b8e4d9505 -virtualenv==20.26.6 \ - --hash=sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48 \ - --hash=sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2 +virtualenv==20.27.0 \ + --hash=sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2 \ + --hash=sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655 wheel==0.44.0 \ --hash=sha256:2376a90c98cc337d18623527a97c31797bd02bad0033d41547043a1cbfbe448f \ --hash=sha256:a29c3f2817e95ab89aa4660681ad547c0e9547f20e75b0562fe7723c9a2a9d49 diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..e35d885 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1 @@ +_build diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d4bb2cb --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/api/index.rst b/docs/api/index.rst new file mode 100644 index 0000000..924876c --- /dev/null +++ b/docs/api/index.rst @@ -0,0 +1,19 @@ +Python API +========== + +.. warning:: + + The Python API is *NOT YET STABLE*. + Function, class, and method names may change between releases + without any deprecation period. + +.. automodule:: venvstacks + + .. rubric:: Modules + + .. autosummary:: + :toctree: + + cli + pack_venv + stacks diff --git a/docs/api/venvstacks.cli.main.rst b/docs/api/venvstacks.cli.main.rst new file mode 100644 index 0000000..2925f3a --- /dev/null +++ b/docs/api/venvstacks.cli.main.rst @@ -0,0 +1,6 @@ +venvstacks.cli.main +=================== + +.. currentmodule:: venvstacks.cli + +.. autofunction:: main \ No newline at end of file diff --git a/docs/api/venvstacks.cli.rst b/docs/api/venvstacks.cli.rst new file mode 100644 index 0000000..dbc55b2 --- /dev/null +++ b/docs/api/venvstacks.cli.rst @@ -0,0 +1,12 @@ +venvstacks.cli +============== + +.. automodule:: venvstacks.cli + + + .. rubric:: Functions + + .. autosummary:: + :toctree: + + main diff --git a/docs/api/venvstacks.pack_venv.convert_symlinks.rst b/docs/api/venvstacks.pack_venv.convert_symlinks.rst new file mode 100644 index 0000000..5f4cb09 --- /dev/null +++ b/docs/api/venvstacks.pack_venv.convert_symlinks.rst @@ -0,0 +1,6 @@ +venvstacks.pack\_venv.convert\_symlinks +======================================= + +.. currentmodule:: venvstacks.pack_venv + +.. autofunction:: convert_symlinks \ No newline at end of file diff --git a/docs/api/venvstacks.pack_venv.create_archive.rst b/docs/api/venvstacks.pack_venv.create_archive.rst new file mode 100644 index 0000000..ad073d8 --- /dev/null +++ b/docs/api/venvstacks.pack_venv.create_archive.rst @@ -0,0 +1,6 @@ +venvstacks.pack\_venv.create\_archive +===================================== + +.. currentmodule:: venvstacks.pack_venv + +.. autofunction:: create_archive \ No newline at end of file diff --git a/docs/api/venvstacks.pack_venv.export_venv.rst b/docs/api/venvstacks.pack_venv.export_venv.rst new file mode 100644 index 0000000..0003c3b --- /dev/null +++ b/docs/api/venvstacks.pack_venv.export_venv.rst @@ -0,0 +1,6 @@ +venvstacks.pack\_venv.export\_venv +================================== + +.. currentmodule:: venvstacks.pack_venv + +.. autofunction:: export_venv \ No newline at end of file diff --git a/docs/api/venvstacks.pack_venv.get_archive_path.rst b/docs/api/venvstacks.pack_venv.get_archive_path.rst new file mode 100644 index 0000000..9d11246 --- /dev/null +++ b/docs/api/venvstacks.pack_venv.get_archive_path.rst @@ -0,0 +1,6 @@ +venvstacks.pack\_venv.get\_archive\_path +======================================== + +.. currentmodule:: venvstacks.pack_venv + +.. autofunction:: get_archive_path \ No newline at end of file diff --git a/docs/api/venvstacks.pack_venv.rst b/docs/api/venvstacks.pack_venv.rst new file mode 100644 index 0000000..27cda38 --- /dev/null +++ b/docs/api/venvstacks.pack_venv.rst @@ -0,0 +1,15 @@ +venvstacks.pack\_venv +===================== + +.. automodule:: venvstacks.pack_venv + + + .. rubric:: Functions + + .. autosummary:: + :toctree: + + convert_symlinks + create_archive + export_venv + get_archive_path diff --git a/docs/api/venvstacks.stacks.ApplicationEnv.rst b/docs/api/venvstacks.stacks.ApplicationEnv.rst new file mode 100644 index 0000000..4d69509 --- /dev/null +++ b/docs/api/venvstacks.stacks.ApplicationEnv.rst @@ -0,0 +1,62 @@ +venvstacks.stacks.ApplicationEnv +================================ + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ApplicationEnv + + + .. automethod:: __init__ + + .. rubric:: Methods + + .. autosummary:: + + ~ApplicationEnv.create_archive + ~ApplicationEnv.create_environment + ~ApplicationEnv.define_archive_build + ~ApplicationEnv.ensure_runtime_dependencies + ~ApplicationEnv.export_environment + ~ApplicationEnv.get_constraint_paths + ~ApplicationEnv.install_build_requirements + ~ApplicationEnv.install_requirements + ~ApplicationEnv.link_base_runtime_paths + ~ApplicationEnv.link_layered_environments + ~ApplicationEnv.lock_requirements + ~ApplicationEnv.remove_build_only_packages + ~ApplicationEnv.report_python_site_details + ~ApplicationEnv.request_export + ~ApplicationEnv.select_operations + + .. rubric:: Attributes + + .. autosummary:: + + ~ApplicationEnv.category + ~ApplicationEnv.env_name + ~ApplicationEnv.env_spec + ~ApplicationEnv.install_target + ~ApplicationEnv.kind + ~ApplicationEnv.launch_module_name + ~ApplicationEnv.linked_constraints_paths + ~ApplicationEnv.linked_dynlib_paths + ~ApplicationEnv.linked_frameworks + ~ApplicationEnv.linked_pylib_paths + ~ApplicationEnv.want_build + ~ApplicationEnv.want_lock + ~ApplicationEnv.want_publish + ~ApplicationEnv.was_built + ~ApplicationEnv.was_created + ~ApplicationEnv.build_path + ~ApplicationEnv.requirements_path + ~ApplicationEnv.index_config + ~ApplicationEnv.env_path + ~ApplicationEnv.pylib_path + ~ApplicationEnv.dynlib_path + ~ApplicationEnv.executables_path + ~ApplicationEnv.python_path + ~ApplicationEnv.env_lock + ~ApplicationEnv.base_python_path + ~ApplicationEnv.tools_python_path + ~ApplicationEnv.py_version + diff --git a/docs/api/venvstacks.stacks.ApplicationSpec.rst b/docs/api/venvstacks.stacks.ApplicationSpec.rst new file mode 100644 index 0000000..5564fc4 --- /dev/null +++ b/docs/api/venvstacks.stacks.ApplicationSpec.rst @@ -0,0 +1,35 @@ +venvstacks.stacks.ApplicationSpec +================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ApplicationSpec + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ApplicationSpec.get_requirements_fname + ~ApplicationSpec.get_requirements_path + + .. rubric:: Attributes + + .. autosummary:: + + ~ApplicationSpec.ENV_PREFIX + ~ApplicationSpec.category + ~ApplicationSpec.env_name + ~ApplicationSpec.kind + ~ApplicationSpec.launch_module_path + ~ApplicationSpec.frameworks + ~ApplicationSpec.runtime + ~ApplicationSpec.name + ~ApplicationSpec.versioned + ~ApplicationSpec.requirements + ~ApplicationSpec.build_requirements + ~ApplicationSpec.platforms + diff --git a/docs/api/venvstacks.stacks.ArchiveBuildMetadata.rst b/docs/api/venvstacks.stacks.ArchiveBuildMetadata.rst new file mode 100644 index 0000000..b6fdfc2 --- /dev/null +++ b/docs/api/venvstacks.stacks.ArchiveBuildMetadata.rst @@ -0,0 +1,27 @@ +venvstacks.stacks.ArchiveBuildMetadata +====================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ArchiveBuildMetadata + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~ArchiveBuildMetadata.layer_name + ~ArchiveBuildMetadata.install_target + ~ArchiveBuildMetadata.requirements_hash + ~ArchiveBuildMetadata.lock_version + ~ArchiveBuildMetadata.locked_at + ~ArchiveBuildMetadata.runtime_name + ~ArchiveBuildMetadata.required_layers + ~ArchiveBuildMetadata.app_launch_module + ~ArchiveBuildMetadata.app_launch_module_hash + ~ArchiveBuildMetadata.archive_build + ~ArchiveBuildMetadata.archive_name + ~ArchiveBuildMetadata.target_platform + diff --git a/docs/api/venvstacks.stacks.ArchiveBuildRequest.rst b/docs/api/venvstacks.stacks.ArchiveBuildRequest.rst new file mode 100644 index 0000000..a428119 --- /dev/null +++ b/docs/api/venvstacks.stacks.ArchiveBuildRequest.rst @@ -0,0 +1,29 @@ +venvstacks.stacks.ArchiveBuildRequest +===================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ArchiveBuildRequest + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~ArchiveBuildRequest.create_archive + ~ArchiveBuildRequest.define_build + ~ArchiveBuildRequest.needs_archive_build + + .. rubric:: Attributes + + .. autosummary:: + + ~ArchiveBuildRequest.env_name + ~ArchiveBuildRequest.env_lock + ~ArchiveBuildRequest.archive_base_path + ~ArchiveBuildRequest.build_metadata + ~ArchiveBuildRequest.needs_build + diff --git a/docs/api/venvstacks.stacks.ArchiveHashes.rst b/docs/api/venvstacks.stacks.ArchiveHashes.rst new file mode 100644 index 0000000..9f39536 --- /dev/null +++ b/docs/api/venvstacks.stacks.ArchiveHashes.rst @@ -0,0 +1,15 @@ +venvstacks.stacks.ArchiveHashes +=============================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ArchiveHashes + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~ArchiveHashes.sha256 + diff --git a/docs/api/venvstacks.stacks.ArchiveMetadata.rst b/docs/api/venvstacks.stacks.ArchiveMetadata.rst new file mode 100644 index 0000000..c9035ba --- /dev/null +++ b/docs/api/venvstacks.stacks.ArchiveMetadata.rst @@ -0,0 +1,28 @@ +venvstacks.stacks.ArchiveMetadata +================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ArchiveMetadata + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~ArchiveMetadata.layer_name + ~ArchiveMetadata.install_target + ~ArchiveMetadata.requirements_hash + ~ArchiveMetadata.lock_version + ~ArchiveMetadata.locked_at + ~ArchiveMetadata.runtime_name + ~ArchiveMetadata.required_layers + ~ArchiveMetadata.app_launch_module + ~ArchiveMetadata.app_launch_module_hash + ~ArchiveMetadata.archive_build + ~ArchiveMetadata.archive_name + ~ArchiveMetadata.target_platform + ~ArchiveMetadata.archive_size + ~ArchiveMetadata.archive_hashes + diff --git a/docs/api/venvstacks.stacks.BuildEnvError.rst b/docs/api/venvstacks.stacks.BuildEnvError.rst new file mode 100644 index 0000000..dee61d4 --- /dev/null +++ b/docs/api/venvstacks.stacks.BuildEnvError.rst @@ -0,0 +1,6 @@ +venvstacks.stacks.BuildEnvError +=============================== + +.. currentmodule:: venvstacks.stacks + +.. autoexception:: BuildEnvError \ No newline at end of file diff --git a/docs/api/venvstacks.stacks.BuildEnvironment.rst b/docs/api/venvstacks.stacks.BuildEnvironment.rst new file mode 100644 index 0000000..4b11373 --- /dev/null +++ b/docs/api/venvstacks.stacks.BuildEnvironment.rst @@ -0,0 +1,52 @@ +venvstacks.stacks.BuildEnvironment +================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: BuildEnvironment + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~BuildEnvironment.all_environments + ~BuildEnvironment.built_environments + ~BuildEnvironment.create_environments + ~BuildEnvironment.environments_to_build + ~BuildEnvironment.environments_to_lock + ~BuildEnvironment.environments_to_publish + ~BuildEnvironment.export_environments + ~BuildEnvironment.get_unmatched_patterns + ~BuildEnvironment.load_archive_metadata + ~BuildEnvironment.load_export_metadata + ~BuildEnvironment.lock_environments + ~BuildEnvironment.publish_artifacts + ~BuildEnvironment.runtimes_to_build + ~BuildEnvironment.runtimes_to_lock + ~BuildEnvironment.select_layers + ~BuildEnvironment.select_operations + ~BuildEnvironment.venvstacks_to_build + ~BuildEnvironment.write_archive_metadata + ~BuildEnvironment.write_artifacts_manifest + ~BuildEnvironment.write_env_metadata + ~BuildEnvironment.write_export_manifest + + .. rubric:: Attributes + + .. autosummary:: + + ~BuildEnvironment.METADATA_DIR + ~BuildEnvironment.METADATA_ENV_DIR + ~BuildEnvironment.METADATA_MANIFEST + ~BuildEnvironment.build_platform + ~BuildEnvironment.requirements_dir_path + ~BuildEnvironment.stack_spec + ~BuildEnvironment.runtimes + ~BuildEnvironment.frameworks + ~BuildEnvironment.applications + ~BuildEnvironment.build_path + diff --git a/docs/api/venvstacks.stacks.EnvStackError.rst b/docs/api/venvstacks.stacks.EnvStackError.rst new file mode 100644 index 0000000..cd421b6 --- /dev/null +++ b/docs/api/venvstacks.stacks.EnvStackError.rst @@ -0,0 +1,6 @@ +venvstacks.stacks.EnvStackError +=============================== + +.. currentmodule:: venvstacks.stacks + +.. autoexception:: EnvStackError \ No newline at end of file diff --git a/docs/api/venvstacks.stacks.EnvironmentExportRequest.rst b/docs/api/venvstacks.stacks.EnvironmentExportRequest.rst new file mode 100644 index 0000000..3f253a0 --- /dev/null +++ b/docs/api/venvstacks.stacks.EnvironmentExportRequest.rst @@ -0,0 +1,29 @@ +venvstacks.stacks.EnvironmentExportRequest +========================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: EnvironmentExportRequest + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~EnvironmentExportRequest.define_export + ~EnvironmentExportRequest.export_environment + ~EnvironmentExportRequest.needs_new_export + + .. rubric:: Attributes + + .. autosummary:: + + ~EnvironmentExportRequest.env_name + ~EnvironmentExportRequest.env_lock + ~EnvironmentExportRequest.export_path + ~EnvironmentExportRequest.export_metadata + ~EnvironmentExportRequest.needs_export + diff --git a/docs/api/venvstacks.stacks.EnvironmentLock.rst b/docs/api/venvstacks.stacks.EnvironmentLock.rst new file mode 100644 index 0000000..6382e6e --- /dev/null +++ b/docs/api/venvstacks.stacks.EnvironmentLock.rst @@ -0,0 +1,32 @@ +venvstacks.stacks.EnvironmentLock +================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: EnvironmentLock + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~EnvironmentLock.get_deployed_name + ~EnvironmentLock.load_valid_metadata + ~EnvironmentLock.update_lock_metadata + + .. rubric:: Attributes + + .. autosummary:: + + ~EnvironmentLock.is_locked + ~EnvironmentLock.last_locked + ~EnvironmentLock.lock_version + ~EnvironmentLock.locked_at + ~EnvironmentLock.requirements_hash + ~EnvironmentLock.requirements_path + ~EnvironmentLock.versioned + ~EnvironmentLock.lock_metadata_path + diff --git a/docs/api/venvstacks.stacks.EnvironmentLockMetadata.rst b/docs/api/venvstacks.stacks.EnvironmentLockMetadata.rst new file mode 100644 index 0000000..a8f20f6 --- /dev/null +++ b/docs/api/venvstacks.stacks.EnvironmentLockMetadata.rst @@ -0,0 +1,18 @@ +venvstacks.stacks.EnvironmentLockMetadata +========================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: EnvironmentLockMetadata + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~EnvironmentLockMetadata.locked_at + ~EnvironmentLockMetadata.requirements_hash + ~EnvironmentLockMetadata.lock_version + diff --git a/docs/api/venvstacks.stacks.ExportMetadata.rst b/docs/api/venvstacks.stacks.ExportMetadata.rst new file mode 100644 index 0000000..6881e39 --- /dev/null +++ b/docs/api/venvstacks.stacks.ExportMetadata.rst @@ -0,0 +1,24 @@ +venvstacks.stacks.ExportMetadata +================================ + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ExportMetadata + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~ExportMetadata.layer_name + ~ExportMetadata.install_target + ~ExportMetadata.requirements_hash + ~ExportMetadata.lock_version + ~ExportMetadata.locked_at + ~ExportMetadata.runtime_name + ~ExportMetadata.required_layers + ~ExportMetadata.app_launch_module + ~ExportMetadata.app_launch_module_hash + diff --git a/docs/api/venvstacks.stacks.ExportedEnvironmentPaths.rst b/docs/api/venvstacks.stacks.ExportedEnvironmentPaths.rst new file mode 100644 index 0000000..9cb30cb --- /dev/null +++ b/docs/api/venvstacks.stacks.ExportedEnvironmentPaths.rst @@ -0,0 +1,18 @@ +venvstacks.stacks.ExportedEnvironmentPaths +========================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: ExportedEnvironmentPaths + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~ExportedEnvironmentPaths.env_paths + ~ExportedEnvironmentPaths.metadata_path + ~ExportedEnvironmentPaths.snippet_paths + diff --git a/docs/api/venvstacks.stacks.FrameworkEnv.rst b/docs/api/venvstacks.stacks.FrameworkEnv.rst new file mode 100644 index 0000000..09368fe --- /dev/null +++ b/docs/api/venvstacks.stacks.FrameworkEnv.rst @@ -0,0 +1,58 @@ +venvstacks.stacks.FrameworkEnv +============================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: FrameworkEnv + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~FrameworkEnv.create_archive + ~FrameworkEnv.create_environment + ~FrameworkEnv.define_archive_build + ~FrameworkEnv.ensure_runtime_dependencies + ~FrameworkEnv.export_environment + ~FrameworkEnv.get_constraint_paths + ~FrameworkEnv.install_build_requirements + ~FrameworkEnv.install_requirements + ~FrameworkEnv.link_base_runtime_paths + ~FrameworkEnv.lock_requirements + ~FrameworkEnv.remove_build_only_packages + ~FrameworkEnv.report_python_site_details + ~FrameworkEnv.request_export + ~FrameworkEnv.select_operations + + .. rubric:: Attributes + + .. autosummary:: + + ~FrameworkEnv.category + ~FrameworkEnv.env_name + ~FrameworkEnv.env_spec + ~FrameworkEnv.install_target + ~FrameworkEnv.kind + ~FrameworkEnv.linked_constraints_paths + ~FrameworkEnv.want_build + ~FrameworkEnv.want_lock + ~FrameworkEnv.want_publish + ~FrameworkEnv.was_built + ~FrameworkEnv.was_created + ~FrameworkEnv.build_path + ~FrameworkEnv.requirements_path + ~FrameworkEnv.index_config + ~FrameworkEnv.env_path + ~FrameworkEnv.pylib_path + ~FrameworkEnv.dynlib_path + ~FrameworkEnv.executables_path + ~FrameworkEnv.python_path + ~FrameworkEnv.env_lock + ~FrameworkEnv.base_python_path + ~FrameworkEnv.tools_python_path + ~FrameworkEnv.py_version + diff --git a/docs/api/venvstacks.stacks.FrameworkSpec.rst b/docs/api/venvstacks.stacks.FrameworkSpec.rst new file mode 100644 index 0000000..cd226b7 --- /dev/null +++ b/docs/api/venvstacks.stacks.FrameworkSpec.rst @@ -0,0 +1,33 @@ +venvstacks.stacks.FrameworkSpec +=============================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: FrameworkSpec + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~FrameworkSpec.get_requirements_fname + ~FrameworkSpec.get_requirements_path + + .. rubric:: Attributes + + .. autosummary:: + + ~FrameworkSpec.ENV_PREFIX + ~FrameworkSpec.category + ~FrameworkSpec.env_name + ~FrameworkSpec.kind + ~FrameworkSpec.runtime + ~FrameworkSpec.name + ~FrameworkSpec.versioned + ~FrameworkSpec.requirements + ~FrameworkSpec.build_requirements + ~FrameworkSpec.platforms + diff --git a/docs/api/venvstacks.stacks.IndexConfig.rst b/docs/api/venvstacks.stacks.IndexConfig.rst new file mode 100644 index 0000000..df39f67 --- /dev/null +++ b/docs/api/venvstacks.stacks.IndexConfig.rst @@ -0,0 +1,28 @@ +venvstacks.stacks.IndexConfig +============================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: IndexConfig + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~IndexConfig.disabled + ~IndexConfig.resolve_lexical_paths + + + .. rubric:: Attributes + + .. autosummary:: + + ~IndexConfig.allow_source_builds + ~IndexConfig.local_wheel_dirs + ~IndexConfig.query_default_index + ~IndexConfig.local_wheel_paths + diff --git a/docs/api/venvstacks.stacks.LayerCategories.rst b/docs/api/venvstacks.stacks.LayerCategories.rst new file mode 100644 index 0000000..cf56500 --- /dev/null +++ b/docs/api/venvstacks.stacks.LayerCategories.rst @@ -0,0 +1,18 @@ +venvstacks.stacks.LayerCategories +================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: LayerCategories + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~LayerCategories.RUNTIMES + ~LayerCategories.FRAMEWORKS + ~LayerCategories.APPLICATIONS + diff --git a/docs/api/venvstacks.stacks.LayerSpecError.rst b/docs/api/venvstacks.stacks.LayerSpecError.rst new file mode 100644 index 0000000..e31007e --- /dev/null +++ b/docs/api/venvstacks.stacks.LayerSpecError.rst @@ -0,0 +1,6 @@ +venvstacks.stacks.LayerSpecError +================================ + +.. currentmodule:: venvstacks.stacks + +.. autoexception:: LayerSpecError \ No newline at end of file diff --git a/docs/api/venvstacks.stacks.LayerSpecMetadata.rst b/docs/api/venvstacks.stacks.LayerSpecMetadata.rst new file mode 100644 index 0000000..a6b4ddc --- /dev/null +++ b/docs/api/venvstacks.stacks.LayerSpecMetadata.rst @@ -0,0 +1,24 @@ +venvstacks.stacks.LayerSpecMetadata +=================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: LayerSpecMetadata + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~LayerSpecMetadata.layer_name + ~LayerSpecMetadata.install_target + ~LayerSpecMetadata.requirements_hash + ~LayerSpecMetadata.lock_version + ~LayerSpecMetadata.locked_at + ~LayerSpecMetadata.runtime_name + ~LayerSpecMetadata.required_layers + ~LayerSpecMetadata.app_launch_module + ~LayerSpecMetadata.app_launch_module_hash + diff --git a/docs/api/venvstacks.stacks.LayerVariants.rst b/docs/api/venvstacks.stacks.LayerVariants.rst new file mode 100644 index 0000000..33cfb24 --- /dev/null +++ b/docs/api/venvstacks.stacks.LayerVariants.rst @@ -0,0 +1,18 @@ +venvstacks.stacks.LayerVariants +=============================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: LayerVariants + + + .. automethod:: __init__ + + .. rubric:: Attributes + + .. autosummary:: + + ~LayerVariants.RUNTIME + ~LayerVariants.FRAMEWORK + ~LayerVariants.APPLICATION + diff --git a/docs/api/venvstacks.stacks.PublishedArchivePaths.rst b/docs/api/venvstacks.stacks.PublishedArchivePaths.rst new file mode 100644 index 0000000..bfbbfe1 --- /dev/null +++ b/docs/api/venvstacks.stacks.PublishedArchivePaths.rst @@ -0,0 +1,15 @@ +venvstacks.stacks.PublishedArchivePaths +======================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: PublishedArchivePaths + + .. rubric:: Attributes + + .. autosummary:: + + ~PublishedArchivePaths.archive_paths + ~PublishedArchivePaths.metadata_path + ~PublishedArchivePaths.snippet_paths + diff --git a/docs/api/venvstacks.stacks.RuntimeEnv.rst b/docs/api/venvstacks.stacks.RuntimeEnv.rst new file mode 100644 index 0000000..a8bf5ad --- /dev/null +++ b/docs/api/venvstacks.stacks.RuntimeEnv.rst @@ -0,0 +1,57 @@ +venvstacks.stacks.RuntimeEnv +============================ + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: RuntimeEnv + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~RuntimeEnv.create_archive + ~RuntimeEnv.create_build_environment + ~RuntimeEnv.create_environment + ~RuntimeEnv.define_archive_build + ~RuntimeEnv.ensure_runtime_dependencies + ~RuntimeEnv.export_environment + ~RuntimeEnv.get_constraint_paths + ~RuntimeEnv.install_build_requirements + ~RuntimeEnv.install_requirements + ~RuntimeEnv.lock_requirements + ~RuntimeEnv.remove_build_only_packages + ~RuntimeEnv.report_python_site_details + ~RuntimeEnv.request_export + ~RuntimeEnv.select_operations + + .. rubric:: Attributes + + .. autosummary:: + + ~RuntimeEnv.category + ~RuntimeEnv.env_name + ~RuntimeEnv.env_spec + ~RuntimeEnv.install_target + ~RuntimeEnv.kind + ~RuntimeEnv.want_build + ~RuntimeEnv.want_lock + ~RuntimeEnv.want_publish + ~RuntimeEnv.was_built + ~RuntimeEnv.was_created + ~RuntimeEnv.build_path + ~RuntimeEnv.requirements_path + ~RuntimeEnv.index_config + ~RuntimeEnv.env_path + ~RuntimeEnv.pylib_path + ~RuntimeEnv.dynlib_path + ~RuntimeEnv.executables_path + ~RuntimeEnv.python_path + ~RuntimeEnv.env_lock + ~RuntimeEnv.base_python_path + ~RuntimeEnv.tools_python_path + ~RuntimeEnv.py_version + diff --git a/docs/api/venvstacks.stacks.RuntimeSpec.rst b/docs/api/venvstacks.stacks.RuntimeSpec.rst new file mode 100644 index 0000000..5d14888 --- /dev/null +++ b/docs/api/venvstacks.stacks.RuntimeSpec.rst @@ -0,0 +1,34 @@ +venvstacks.stacks.RuntimeSpec +============================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: RuntimeSpec + + + .. automethod:: __init__ + + + .. rubric:: Methods + + .. autosummary:: + + ~RuntimeSpec.get_requirements_fname + ~RuntimeSpec.get_requirements_path + + .. rubric:: Attributes + + .. autosummary:: + + ~RuntimeSpec.ENV_PREFIX + ~RuntimeSpec.category + ~RuntimeSpec.env_name + ~RuntimeSpec.kind + ~RuntimeSpec.py_version + ~RuntimeSpec.fully_versioned_name + ~RuntimeSpec.name + ~RuntimeSpec.versioned + ~RuntimeSpec.requirements + ~RuntimeSpec.build_requirements + ~RuntimeSpec.platforms + diff --git a/docs/api/venvstacks.stacks.StackExportRequest.rst b/docs/api/venvstacks.stacks.StackExportRequest.rst new file mode 100644 index 0000000..560b0ac --- /dev/null +++ b/docs/api/venvstacks.stacks.StackExportRequest.rst @@ -0,0 +1,13 @@ +venvstacks.stacks.StackExportRequest +==================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: StackExportRequest + + .. rubric:: Attributes + + .. autosummary:: + + ~StackExportRequest.layers + diff --git a/docs/api/venvstacks.stacks.StackPublishingRequest.rst b/docs/api/venvstacks.stacks.StackPublishingRequest.rst new file mode 100644 index 0000000..0c06b84 --- /dev/null +++ b/docs/api/venvstacks.stacks.StackPublishingRequest.rst @@ -0,0 +1,13 @@ +venvstacks.stacks.StackPublishingRequest +======================================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: StackPublishingRequest + + .. rubric:: Attributes + + .. autosummary:: + + ~StackPublishingRequest.layers + diff --git a/docs/api/venvstacks.stacks.StackPublishingResult.rst b/docs/api/venvstacks.stacks.StackPublishingResult.rst new file mode 100644 index 0000000..c68203e --- /dev/null +++ b/docs/api/venvstacks.stacks.StackPublishingResult.rst @@ -0,0 +1,13 @@ +venvstacks.stacks.StackPublishingResult +======================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: StackPublishingResult + + .. rubric:: Attributes + + .. autosummary:: + + ~StackPublishingResult.layers + diff --git a/docs/api/venvstacks.stacks.StackSpec.rst b/docs/api/venvstacks.stacks.StackSpec.rst new file mode 100644 index 0000000..dfa0841 --- /dev/null +++ b/docs/api/venvstacks.stacks.StackSpec.rst @@ -0,0 +1,29 @@ +venvstacks.stacks.StackSpec +=========================== + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: StackSpec + + .. automethod:: __init__ + + .. rubric:: Methods + + .. autosummary:: + + ~StackSpec.all_environment_specs + ~StackSpec.define_build_environment + ~StackSpec.load + ~StackSpec.resolve_lexical_path + + .. rubric:: Attributes + + .. autosummary:: + + ~StackSpec.spec_path + ~StackSpec.runtimes + ~StackSpec.frameworks + ~StackSpec.applications + ~StackSpec.requirements_dir_path + ~StackSpec.build_platform + diff --git a/docs/api/venvstacks.stacks.TargetPlatform.rst b/docs/api/venvstacks.stacks.TargetPlatform.rst new file mode 100644 index 0000000..861b951 --- /dev/null +++ b/docs/api/venvstacks.stacks.TargetPlatform.rst @@ -0,0 +1,16 @@ +venvstacks.stacks.TargetPlatform +================================ + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: TargetPlatform + + .. rubric:: Attributes + + .. autosummary:: + + ~TargetPlatform.WINDOWS + ~TargetPlatform.LINUX + ~TargetPlatform.MACOS_APPLE + ~TargetPlatform.MACOS_INTEL + diff --git a/docs/api/venvstacks.stacks.TargetPlatforms.rst b/docs/api/venvstacks.stacks.TargetPlatforms.rst new file mode 100644 index 0000000..8c994b5 --- /dev/null +++ b/docs/api/venvstacks.stacks.TargetPlatforms.rst @@ -0,0 +1,16 @@ +venvstacks.stacks.TargetPlatforms +================================= + +.. currentmodule:: venvstacks.stacks + +.. autoclass:: TargetPlatforms + + .. rubric:: Attributes + + .. autosummary:: + + ~TargetPlatforms.WINDOWS + ~TargetPlatforms.LINUX + ~TargetPlatforms.MACOS_APPLE + ~TargetPlatforms.MACOS_INTEL + diff --git a/docs/api/venvstacks.stacks.rst b/docs/api/venvstacks.stacks.rst new file mode 100644 index 0000000..c87621d --- /dev/null +++ b/docs/api/venvstacks.stacks.rst @@ -0,0 +1,47 @@ +venvstacks.stacks +================= + +.. automodule:: venvstacks.stacks + + + .. rubric:: Classes + + .. autosummary:: + :toctree: + + ApplicationEnv + ApplicationSpec + ArchiveBuildMetadata + ArchiveBuildRequest + ArchiveHashes + ArchiveMetadata + BuildEnvironment + EnvironmentExportRequest + EnvironmentLock + EnvironmentLockMetadata + ExportMetadata + ExportedEnvironmentPaths + FrameworkEnv + FrameworkSpec + IndexConfig + LayerCategories + LayerSpecMetadata + LayerVariants + PublishedArchivePaths + RuntimeEnv + RuntimeSpec + StackExportRequest + StackPublishingRequest + StackPublishingResult + StackSpec + TargetPlatform + TargetPlatforms + + .. rubric:: Exceptions + + .. autosummary:: + :toctree: + + BuildEnvError + EnvStackError + LayerSpecError diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..9bae84c --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,60 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "venvstacks" +copyright = "2024, LM Studio" +author = "LM Studio" +release = "0.1" + + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + # first-party extensions + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinx.ext.duration", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", +] + +templates_path = ["_templates"] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] + + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "furo" +html_static_path = ["_static"] + +# Disable the generation of the various indexes +html_use_modindex = False +html_use_index = False + + +# -- Options for intersphinx ---------------------------------------------------------- + +# Run `tox -e regen-apidocs` to regenerate the API stub pages +autosummary_generate = False + +# -- Options for intersphinx ---------------------------------------------------------- + +intersphinx_mapping = { + "py": ("https://docs.python.org/3", None), +} + + +# -- Options for extlinks ------------------------------------------------------------- + +extlinks = { + "issue": ("https://github.com/lmstudio/venvstacks/issues/%s", "#%s"), + "pr": ("https://github.com/lmstudio/venvstacks/pull/%s", "PR #%s"), + "pypi": ("https://pypi.org/project/%s/", "%s"), +} diff --git a/docs/design.rst b/docs/design.rst new file mode 100644 index 0000000..b170b4c --- /dev/null +++ b/docs/design.rst @@ -0,0 +1,63 @@ +Design Discussion +================= + +Why does ``venvstacks`` exist? +------------------------------ + +``venvstacks`` exists because LM Studio were looking for a way +to integrate Python based AI projects into their cross-platform +desktop application, and after trialling other potential mechanisms, +decided that there was a genuine gap in the Python packaging tooling +landscape, and invested in building something new to fill that need. + + +What other existing projects were considered? +--------------------------------------------- + +There were two primary existing projects considered as potential +solutions: + +* :pypi:`wagon` +* :pypi:`conda-pack` + +Similar to ``venvstacks``, ``wagon`` aims to avoid needing to download +Python packages on the target deployment system. However, it does +this by shipping the individual packages and creating fresh virtual +environments on the target system, which means much more work has to +happen at installation time. While ``venvstacks`` isn't able to completely +eliminate the need to adjust the deployed environments post-installation, +the amount of work needed is substantially less than if the environments +were being assembled from individual wheels on the target systems. + +``conda-pack`` proved unsuitable not because of any limitations in +``conda-pack`` itself, but because ``conda``'s notion of +`environment stacking `__ +refers specifically to accessing the ``PATH`` entries for other +environments, it doesn't refer to being able combine ``sys.path`` +across multiple environments. + +Splitting environments into layers the way ``venvstacks`` does +really doesn't align well with the way the ``conda`` dependency +resolver works, so it ended up making more sense to design +``venvstacks`` to work with ``venv`` and ``pip``. + +The assorted "Python application packaging" utilities that produce +standalone platform native executables or Python :py:mod:`zipapp` +archives were eliminated from consideration as they lacked the ability +to readily share the large common framework components that feature +heavily in the Python AI ecosystem across different applications. + +Why use ``python-build-standalone`` for the base runtimes? +---------------------------------------------------------- + +The short answer to this question is "Because that's what :pypi:`pdm` uses, +and ``venvstacks`` was already using ``pdm`` as its project management tool". + +The longer answer is that there's a genuinely strong alignment between the +properties that the ``python-build-standalone`` maintainers aim to provide +in their published binaries, and the characteristics that ``venvstacks`` +needs in its base runtime layers. + +Supporting additional base runtime layer providers (such as :pypi:`conda`) +could be a genuinely interesting capability, but there are no current +plans to implement such a mechanism. diff --git a/docs/development/index.rst b/docs/development/index.rst new file mode 100644 index 0000000..b71ae0c --- /dev/null +++ b/docs/development/index.rst @@ -0,0 +1,186 @@ +.. _dev-guide: + +Development +=========== + +(With thanks to pip's `Getting Started`_ guide for the general structure here!) + +This document aims to get you setup to work on venvstacks and to act as a guide +and reference to the development setup. If you face any issues during this +process, please `open an issue`_ about it on the issue tracker. + + +Get the source code +------------------- + +To work on venvstacks, you first need to get the source code. The source code is +available on `GitHub`_. + +.. code-block:: console + + $ git clone https://github.com/lmstudio/venvstacks + $ cd venvstacks + + +Development Environment +----------------------- + +In order to work on venvstacks, you need to install +:pypi:`pdm`, :pypi:`tox`, and :pypi:`tox-pdm`. + +Given these tools, the default development environment can be set up +and other commands executed as described below. + + +Running from the source tree +---------------------------- + +To run venvstacks from your source tree during development, use pdm +to set up an editable install in the default venv: + +.. code-block:: console + + $ pdm sync --dev + +venvstacks can then be executed via the ``-m`` switch: + +.. code-block:: console + + $ .venv/bin/python -m venvstacks --help + + Usage: python -m venvstacks [OPTIONS] COMMAND [ARGS]... + + Lock, build, and publish Python virtual environment stacks. + + ╭─ Options ───────────────────────────────────────────────────────────────────────╮ + │ --help Show this message and exit. │ + ╰─────────────────────────────────────────────────────────────────────────────────╯ + ╭─ Commands ──────────────────────────────────────────────────────────────────────╮ + │ build Build (/lock/publish) Python virtual environment stacks. │ + │ local-export Export layer environments for Python virtual environment stacks. │ + │ lock Lock layer requirements for Python virtual environment stacks. │ + │ publish Publish layer archives for Python virtual environment stacks. │ + ╰─────────────────────────────────────────────────────────────────────────────────╯ + + +Code consistency checks +----------------------- + +The project source code is autoformatted and linted using :pypi:`ruff`. +It also uses :pypi:`mypy` in strict mode to statically check that Python APIs +are being accessed as expected. + +All of these commands can be invoked via tox: + +.. code-block:: console + + $ tox -e format + +.. code-block:: console + + $ tox -e lint + +.. code-block:: console + + $ tox -e typecheck + +.. note:: + + Avoid using ``# noqa`` comments to suppress these warnings - wherever + possible, warnings should be fixed instead. ``# noqa`` comments are + reserved for rare cases where the recommended style causes severe + readability problems, and there isn't a more explicit mechanism + (such as ``typing.cast``) to indicate which check is being skipped. + + ``# fmt: off/on`` and ``# fmt: skip`` comments may be used as needed + when the autoformatter makes readability worse instead of better + (for example, collapsing lists to a single line when they intentionally + cover multiple lines, or ) + + +Running tests locally +--------------------- + +The project's tests are written using the :pypi:`pytest` test framework and the +standard library's :mod:`unittest` module. :pypi:`tox` is used to automate the +setup and execution of these tests across multiple Python versions. + +Some of the tests build and deploy full environment stacks, which makes them +take a long time to run (5+ minutes for the sample project build and export, +even with fully cached dependencies). + +Local test runs will usually want to skip these slow tests: + +.. code-block:: console + + $ tox -m test -- -m "not slow" + +The example above runs tests against the default Python version configured in +``tox.ini``. You can also use other defined versions by specifying the target +environment directly: + +.. code-block:: console + + $ tox -e py3.11 -- -m "not slow" + +``tox`` has been configured to forward any additional arguments it is given to +``pytest`` (as shown in the examples). This enables the use of pytest's `rich CLI`_. +In particular, you can select tests using all the optionts that pytest provides: + +.. code-block:: console + + $ # Using file name + $ tox -m test -- tests/test_basics.py + $ # Using markers + $ tox -m test -- -m "not slow" + $ # Using keyword text search + $ tox -m test -- -k "lock and not publish" + +Additional notes on running and updating the tests can be found in the +`testing README file`_. + + +Tests with committed expected output +'''''''''''''''''''''''''''''''''''' + +The "sample project" test cases primarily work by checking that relocking and +rebuilding the sample project produces the same locked requirements +files and the same publication metadata. + +This means those test cases will fail when the expected output is changed +intentionally, such as choosing a new baseline date for the sample project +lockfiles, adding new fields to the expected metadata, or changing the +expected contents of the defined environment layers. + +PRs that modify the ``tests/expected-output-config.yml`` file will trigger +a GitHub workflows that checks all other tests pass, and then generates a +new PR targeting the triggering PR branch. The changes to the expected +output files can then be reviewed to confirm they match the expected +impact of the changes that were (for example, launch module changes +should only affect the hashes and sizes of the application layer +archives that include those launch modules). + +If the original PR is not correct, then it can be retriggered by +closing and reopening the PR once the relevants fixes have been +implemented. + + +Building Documentation +---------------------- + +pip's documentation is built using :pypi:`Sphinx`. The documentation is written +in reStructuredText. + +To build it locally, run: + +.. code-block:: console + + $ tox -e docs + +The built documentation can be found in the ``docs/_build`` folder. + +.. _`Getting Started`: https://pip.pypa.io/en/stable/development/getting-started/ +.. _`open an issue`: https://github.com/lmstudio/venvstacks/issues/new?title=Trouble+with+development+environment +.. _`rich CLI`: https://docs.pytest.org/en/stable/how-to/usage.html#specifying-which-tests-to-run +.. _`GitHub`: https://github.com/lmstudio/venvstacks +.. _`testing README file`: https://github.com/lmstudio-ai/venvstacks/blob/main/tests/README.md diff --git a/docs/glossary.rst b/docs/glossary.rst new file mode 100644 index 0000000..522634d --- /dev/null +++ b/docs/glossary.rst @@ -0,0 +1,67 @@ +Essential Terms and Concepts +============================ + +.. glossary:: + + archive + A packed environment layer for distribution and deployment. Contains + either a fully built base runtime environment :term:`layer`, or + else a built layered environment that depends on the other + layers specified in its metadata. + + environment + build environment + deployed environment + layered environment + A base runtime environment (built from a base runtime layer definition), + or a layered virtual environment (built from an application or framework + layer definition). + May be a build environment, or a deployed environment. + Deployed environments may be created either directly (via local export), + or indirectly (via archive creation and unpacking). + Exported environments and archive deployments contain slightly + different metadata (since there are no archive details in the + exported environment metadata). + + export + local export + Locally publishing an environment on the same machine, + skipping the archive-and-unpack step, and automatically + running the post-installation step. Primarily intended + to speed up development iteration cycles when testing + stack builds and application layer launch modules, but may + also be used to export environments that normally use symlinks + to target filesystems which don't support them (such as USB keys). + (Note that transferring USB keys between systems is still likely + to run into problems related to absolute paths no longer being + correct, as Windows drive letters and POSIX mount points are + highly likely to differ across machines). + + layer + application layer + base runtime layer + framework layer + A definition of a set of Python requirements which will be pinned + for building and publication as a single consolidated :term:`archive`. + Layer definitions are categorised as follows: + + * *base runtime layers*: these layers specify a base Python runtime which + is used as a foundation for one or more environment stacks. Any + requirements specified as part of a base runtime layer are installed + directly into the base runtime (there is no virtual environment defined). + * *framework layers*: these layers primarily contain large dependencies + (such as :pypi:`pytorch`) which should not be published multiple times, + even when they are used by multiple applications. Applications are + constrained to use the versions of any packages installed in the + framework layers they depend on. Each framework layer depends on a + specific runtime layer. + * *application layers*: these layers specify the actual deployed Python + applications which embedding applications will invoke. Applications + depend on one or more framework layers + + stack + environment stack + An application layer with its supporting framework and base runtime layers. + + stack specification + A ``venvstacks.toml`` file that definez one or more environment stacks. diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..06bc82c --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,16 @@ +.. venvstacks documentation master file, created by + sphinx-quickstart on Mon Oct 21 20:08:31 2024. + +========================================== +Welcome to ``venvstacks``'s documentation! +========================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + overview + glossary + design + api/index + development/index diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..32bb245 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/overview.rst b/docs/overview.rst new file mode 100644 index 0000000..7440a1c --- /dev/null +++ b/docs/overview.rst @@ -0,0 +1,197 @@ +Layered Virtual Environment Stacks +================================== + +``venvstacks`` uses Python's ``sitecustomize.py`` environment setup feature +to chain together three layers of Python virtual environments: + +* "Runtime" layers: environments containing the desired version of a specific Python interpreter +* "Framework" layers: environments containing desired versions of key Python frameworks +* "Application" layers: environments containing components to be launched directly + +While the layers are archived and published separately, their dependency locking is integrated, +allowing the application layers to share dependencies installed in the framework layers, +and the framework layers to share dependencies installed in the runtime layers. + + +Installing +---------- + +``venvstacks`` is available from the :pypi:`Python Package Index `, +and can be installed with :pypi:`pip`: + +.. code-block:: console + + $ pip install --user venvstacks + +The command line help also provides additional usage information: + +.. code-block:: console + + $ .venv/bin/python -m venvstacks --help + + Usage: python -m venvstacks [OPTIONS] COMMAND [ARGS]... + + Lock, build, and publish Python virtual environment stacks. + + ╭─ Options ───────────────────────────────────────────────────────────────────────╮ + │ --help Show this message and exit. │ + ╰─────────────────────────────────────────────────────────────────────────────────╯ + ╭─ Commands ──────────────────────────────────────────────────────────────────────╮ + │ build Build (/lock/publish) Python virtual environment stacks. │ + │ local-export Export layer environments for Python virtual environment stacks. │ + │ lock Lock layer requirements for Python virtual environment stacks. │ + │ publish Publish layer archives for Python virtual environment stacks. │ + ╰─────────────────────────────────────────────────────────────────────────────────╯ + +.. note:: + + The ``venvstacks`` command is currently only available via the Python interpreter's + :py:option:`-m` switch, so Python command execution utilities like ``pipx run`` + and ``uvx`` don't work yet. + However, direct execution as ``venvstacks`` is expected to be + :issue:`supported in a future release <26>`. + + +Defining environment stacks +--------------------------- + +The environment layers to be published are defined in a ``venvstacks.toml`` stack specification, +with a separate array of tables for each kind of layer definition. + +For example, the following specification defines a pair of applications which use +`scikit-learn `__` as a shared framework layer with +`numpy `__ preinstalled in the runtime layer, +all running in a controlled Python 3.11 base runtime: + +.. code-block:: toml + + [[runtimes]] + name = "cpython@3.11" + fully_versioned_name = "cpython@3.11.10" + requirements = [ + "numpy", + ] + + [[frameworks]] + name = "sklearn" + runtime = "cpython@3.11" + requirements = [ + "scikit-learn", + ] + + [[applications]] + name = "classification-demo" + launch_module = "launch_modules/sklearn_classification.py" + frameworks = ["sklearn"] + requirements = [ + "scikit-learn", + ] + + [[applications]] + name = "clustering-demo" + launch_module = "launch_modules/sklearn_clustering.py" + frameworks = ["sklearn"] + requirements = [ + "scikit-learn", + ] + +Locking environment stacks +-------------------------- + +.. code-block:: console + + $ python -m venvstacks lock sklearn_demo/venvstacks.toml + +The ``lock`` subcommand takes the defined layer requirements from the specification, +and uses them to perform a complete combined resolution of all of the environment stacks +that ensures the different layers can be published separately, +but still work as expected when deployed to a target system. + +The locking mechanism is defined such that only changes to modules a given layer +uses from lower layers affect them, +rather than upper layers needing to be rebuilt for *every* change to a lower layer. + +Building environment stacks +--------------------------- + +.. code-block:: console + + $ python -m venvstacks build sklearn_demo/venvstacks.toml + +The ``build`` subcommand performs the step of converting the layer specifications +and their locked requirements into a working Python environment +(either a base runtime environment, +or a layered virtual environment based on one of the defined runtime environments). +If the environments have not already been explicitly locked, +the build step will lock them as necessary. + +This command is also a "build pipeline" command that allows locking, building, +and publishing to be performed in a single step (see the command line help for details). + +Publishing environment layer archives +------------------------------------- + +.. code-block:: console + + $ python -m venvstacks publish --tag-outputs --output-dir demo_artifacts sklearn_demo/venvstacks.toml + +Once the environments have been successfully built, +the ``publish`` command allows each layer to be converted to a separate +`reproducible `__` binary archive suitable +for transferring to another system, unpacking, and using the unpacked environments +to run the included applications (needing only a small post-installation step using +a Python script embedded in the built layer archives to correctly relink the deployed +environments with each other in their deployed location on the target system). + +Metadata regarding the layer definitions and the published artifacts is published +alongside the published archives (to ``demo_artifacts/__venvstacks__/`` in the given example). +This metadata captures both input details (such as the hashes of the locked requirements +and the included launch modules) and output details +(such as the exact size and exact hash of the built layer archive). + +Locally exporting environment stacks +------------------------------------ + +.. code-block:: console + + $ python -m venvstacks local-export --output-dir demo_export sklearn_demo/venvstacks.toml + +Given that even considering the use of ``venvstacks`` implies that some layer archives may be of +significant size (a fully built `pytorch` archive weighs in at multiple gigabytes, for example), +packing and unpacking the layer archives can take a substantial amount of time. + +To avoid that overhead when iterating on layer definitions and launch module details, +the ``local-export`` subcommand allows the built environments to be copied to a different +location on the same system, with most of the same filtering steps applied as would be +applied when performing the archive pack-and-unpack steps (the omissions are details +related to reproducible builds, like clamping the maximum file modification times to known values). + +Locally exporting environments produces much of the same metadata as publishing layer archives, +but the details related specifically to the published archive (such as its size and expected +contents hash) are necessarily omitted. + +Contributing to ``venvstacks`` development +------------------------------------------ + +``venvstacks`` is MIT Licensed and `developed on GitHub `__. + +If you have a suitable use case, +the easiest way to contribute to ``venvstacks`` development is just to try it out, +and let us know how that goes. What did you like, what did you dislike, what just plain broke? + +If anything does break, +then please `open an issue `__ +(if the problem hasn't already been reported). +If you're not sure if some behaviour is a bug or not, +or would just like to provide general feedback rather than file specific issues or suggestions, +the following Discord channels are the best way to get directly in touch with the developers: + +* Discuss ``venvstacks`` in general in the ``#venvstacks`` channel on the + `PyPA Discord Server `__. +* Discuss the use of ``venvstacks`` in LM Studio in the ``#dev-chat`` channel on the + `LM Studio Discord Server `__. + +The `"Packaging" category `__ on +`discuss.python.org `__ is also a reasonable place to provide feedback. + +For additional information, consult the :ref:`developer documentation ` diff --git a/docs/regen-api-docs.sh b/docs/regen-api-docs.sh new file mode 100755 index 0000000..241c285 --- /dev/null +++ b/docs/regen-api-docs.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# See http://redsymbol.net/articles/unofficial-bash-strict-mode/ for benefit of these options +set -euo pipefail +IFS=$'\n\t' + +echo "API docs regen disabled by default (as it overwrites existing edits)" +exit 1 + +# sphinx-autogen -o docs/api docs/api/venvstacks.*.rst diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..eab3e89 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,81 @@ +# This file is @generated by PDM. +# Please do not edit it manually. + +alabaster==1.0.0 +anyio==4.6.2.post1 +attrs==24.2.0 +babel==2.16.0 +beautifulsoup4==4.12.3 +blinker==1.8.2 +build==1.2.2.post1 +cachetools==5.5.0 +certifi==2024.8.30 +chardet==5.2.0 +charset-normalizer==3.4.0 +click==8.1.7 +colorama==0.4.6 +dep-logic==0.4.9 +distlib==0.3.9 +docutils==0.21.2 +filelock==3.16.1 +findpython==0.6.2 +furo==2024.8.6 +h11==0.14.0 +hishel==0.0.33 +httpcore==1.0.6 +httpx[socks]==0.27.2 +idna==3.10 +imagesize==1.4.1 +iniconfig==2.0.0 +installer==0.7.0 +jinja2==3.1.4 +markdown-it-py==3.0.0 +markupsafe==3.0.2 +mdurl==0.1.2 +msgpack==1.1.0 +mypy==1.12.1 +mypy-extensions==1.0.0 +packaging==24.1 +pbs-installer==2024.10.10 +pdm==2.19.3 +pip==24.2 +pip-tools==7.4.1 +platformdirs==4.3.6 +pluggy==1.5.0 +pygments==2.18.0 +pyproject-api==1.8.0 +pyproject-hooks==1.2.0 +pytest==8.3.3 +pytest-subtests==0.13.1 +python-dotenv==1.0.1 +requests==2.32.3 +resolvelib==1.0.1 +rich==13.9.2 +ruff==0.7.0 +setuptools==75.2.0 +shellingham==1.5.4 +sniffio==1.3.1 +snowballstemmer==2.2.0 +socksio==1.0.0 +soupsieve==2.6 +sphinx==8.1.3 +sphinx-basic-ng==1.0.0b2 +sphinxcontrib-applehelp==2.0.0 +sphinxcontrib-devhelp==2.0.0 +sphinxcontrib-htmlhelp==2.1.0 +sphinxcontrib-jsmath==1.0.1 +sphinxcontrib-qthelp==2.0.0 +sphinxcontrib-serializinghtml==2.0.0 +tomlkit==0.13.2 +tox==4.23.0 +tox-gh==1.4.4 +tox-pdm==0.7.2 +truststore==0.9.2 +typer-slim==0.12.5 +typing-extensions==4.12.2 +unearth==0.17.2 +urllib3==2.2.3 +uv==0.4.21 +virtualenv==20.27.0 +wheel==0.44.0 +. # this package diff --git a/lock_dev_venv.sh b/lock_dev_venv.sh index e0a7fc4..1b4b0bb 100755 --- a/lock_dev_venv.sh +++ b/lock_dev_venv.sh @@ -16,3 +16,7 @@ echo "Exported $ci_bootstrap_file" ci_constraints_file="ci-constraints.txt" pdm export --dev --no-extras -o "$ci_constraints_file" echo "Exported $ci_constraints_file" +# Export the docs build dependencies for the sphinx build +docs_requirements_file="docs/requirements.txt" +pdm export --dev --self --no-hashes -o "$docs_requirements_file" +echo "Exported $docs_requirements_file" diff --git a/pdm.lock b/pdm.lock index 8bfda6e..2e58dcb 100644 --- a/pdm.lock +++ b/pdm.lock @@ -2,10 +2,10 @@ # It is not intended for manual editing. [metadata] -groups = ["default", "bootstrap", "dev", "git"] +groups = ["default", "bootstrap", "dev", "docs"] strategy = ["inherit_metadata"] lock_version = "4.5.0" -content_hash = "sha256:33249953f549d76f22722b4a6287cfa47235e550ffdf44b4a9202cd38e9f9c37" +content_hash = "sha256:4282beefc4ca59510cc96299ef8d8d087145393f52982332332f43ad12843a3b" [[metadata.targets]] requires_python = ">=3.11" @@ -31,6 +31,17 @@ platform = "macos_12_0_x86_64" requires_python = ">=3.11" platform = "macos_12_0_arm64" +[[package]] +name = "alabaster" +version = "1.0.0" +requires_python = ">=3.10" +summary = "A light, configurable Sphinx theme" +groups = ["docs"] +files = [ + {file = "alabaster-1.0.0-py3-none-any.whl", hash = "sha256:fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b"}, + {file = "alabaster-1.0.0.tar.gz", hash = "sha256:c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e"}, +] + [[package]] name = "anyio" version = "4.6.2.post1" @@ -62,6 +73,34 @@ files = [ {file = "attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346"}, ] +[[package]] +name = "babel" +version = "2.16.0" +requires_python = ">=3.8" +summary = "Internationalization utilities" +groups = ["docs"] +dependencies = [ + "pytz>=2015.7; python_version < \"3.9\"", +] +files = [ + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, +] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +requires_python = ">=3.6.0" +summary = "Screen-scraping library" +groups = ["docs"] +dependencies = [ + "soupsieve>1.2", +] +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + [[package]] name = "blinker" version = "1.8.2" @@ -107,7 +146,7 @@ name = "certifi" version = "2024.8.30" requires_python = ">=3.6" summary = "Python package for providing Mozilla's CA Bundle." -groups = ["default", "bootstrap"] +groups = ["default", "bootstrap", "docs"] files = [ {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, @@ -124,6 +163,32 @@ files = [ {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, ] +[[package]] +name = "charset-normalizer" +version = "3.4.0" +requires_python = ">=3.7.0" +summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +groups = ["docs"] +files = [ + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +] + [[package]] name = "click" version = "8.1.7" @@ -144,7 +209,7 @@ name = "colorama" version = "0.4.6" requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" summary = "Cross-platform colored terminal text." -groups = ["default", "dev"] +groups = ["default", "dev", "docs"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, @@ -175,24 +240,14 @@ files = [ ] [[package]] -name = "dulwich" -version = "0.22.1" -requires_python = ">=3.7" -summary = "Python Git Library" -groups = ["git"] -dependencies = [ - "setuptools; python_version >= \"3.12\"", - "typing-extensions; python_version <= \"3.7\"", - "urllib3>=1.25", -] +name = "docutils" +version = "0.21.2" +requires_python = ">=3.9" +summary = "Docutils -- Python Documentation Utilities" +groups = ["docs"] files = [ - {file = "dulwich-0.22.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:82f26e592e9a36ab33bcdb419c7d53320e26c85dfc254cdb84f5f561a2fcaabf"}, - {file = "dulwich-0.22.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e90b8a2f24149c5803b733a24f1a016a2943b1f5a9ab2360db545e4638354c35"}, - {file = "dulwich-0.22.1-cp311-cp311-win_amd64.whl", hash = "sha256:a18d1392eabd02f337dcba23d723a4dcca87274ce8693cf88e6320f38bc3fdcd"}, - {file = "dulwich-0.22.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:12482e318895da9acabea7c0cc70b35d36833e7cb2def511ab3a63617f5c1af3"}, - {file = "dulwich-0.22.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6dc42afedc8cda4f2fd15a06d2e9e41281074a02cdf31bb2e0dde4d80766a408"}, - {file = "dulwich-0.22.1-cp312-cp312-win_amd64.whl", hash = "sha256:9d19f04ecd4628a0e4587b4c4e98e040b87924c1362ae5aa27420435f05d5dd8"}, - {file = "dulwich-0.22.1.tar.gz", hash = "sha256:e36d85967cfbf25da1c7bc3d6921adc5baa976969d926aaf1582bd5fd7e94758"}, + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, ] [[package]] @@ -208,7 +263,7 @@ files = [ [[package]] name = "findpython" -version = "0.6.1" +version = "0.6.2" requires_python = ">=3.8" summary = "A utility to find python versions on your system" groups = ["default", "bootstrap"] @@ -216,8 +271,25 @@ dependencies = [ "packaging>=20", ] files = [ - {file = "findpython-0.6.1-py3-none-any.whl", hash = "sha256:1fb4d709205de185b0561900267dfff64a841c910fe28d6038b2394ff925a81a"}, - {file = "findpython-0.6.1.tar.gz", hash = "sha256:56e52b409a92bcbd495cf981c85acf137f3b3e51cc769b46eba219bb1ab7533c"}, + {file = "findpython-0.6.2-py3-none-any.whl", hash = "sha256:bda62477f858ea623ef2269f5e734469a018104a5f6c0fd9317ba238464ddb76"}, + {file = "findpython-0.6.2.tar.gz", hash = "sha256:e0c75ba9f35a7f9bb4423eb31bd17358cccf15761b6837317719177aeff46723"}, +] + +[[package]] +name = "furo" +version = "2024.8.6" +requires_python = ">=3.8" +summary = "A clean customisable Sphinx documentation theme." +groups = ["docs"] +dependencies = [ + "beautifulsoup4", + "pygments>=2.7", + "sphinx-basic-ng>=1.0.0.beta2", + "sphinx<9.0,>=6.0", +] +files = [ + {file = "furo-2024.8.6-py3-none-any.whl", hash = "sha256:6cd97c58b47813d3619e63e9081169880fbe331f0ca883c871ff1f3f11814f5c"}, + {file = "furo-2024.8.6.tar.gz", hash = "sha256:b63e4cee8abfc3136d3bc03a3d45a76a850bada4d6374d24c1716b0e01394a01"}, ] [[package]] @@ -303,12 +375,23 @@ name = "idna" version = "3.10" requires_python = ">=3.6" summary = "Internationalized Domain Names in Applications (IDNA)" -groups = ["default", "bootstrap"] +groups = ["default", "bootstrap", "docs"] files = [ {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[[package]] +name = "imagesize" +version = "1.4.1" +requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +summary = "Getting image size from png/jpeg/jpeg2000/gif file" +groups = ["docs"] +files = [ + {file = "imagesize-1.4.1-py2.py3-none-any.whl", hash = "sha256:0d8d18d08f840c19d0ee7ca1fd82490fdc3729b7ac93f49870406ddde8ef8d8b"}, + {file = "imagesize-1.4.1.tar.gz", hash = "sha256:69150444affb9cb0d5cc5a92b3676f0b2fb7cd9ae39e947a5e11a36b4497cd4a"}, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -331,6 +414,20 @@ files = [ {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +requires_python = ">=3.7" +summary = "A very fast and expressive template engine." +groups = ["docs"] +dependencies = [ + "MarkupSafe>=2.0", +] +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -345,6 +442,32 @@ files = [ {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, ] +[[package]] +name = "markupsafe" +version = "3.0.2" +requires_python = ">=3.9" +summary = "Safely add untrusted strings to HTML/XML markup." +groups = ["docs"] +files = [ + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, +] + [[package]] name = "mdurl" version = "0.1.2" @@ -383,7 +506,7 @@ files = [ [[package]] name = "mypy" -version = "1.12.0" +version = "1.12.1" requires_python = ">=3.8" summary = "Optional static typing for Python" groups = ["dev"] @@ -393,23 +516,23 @@ dependencies = [ "typing-extensions>=4.6.0", ] files = [ - {file = "mypy-1.12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4b86de37a0da945f6d48cf110d5206c5ed514b1ca2614d7ad652d4bf099c7de7"}, - {file = "mypy-1.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:20c7c5ce0c1be0b0aea628374e6cf68b420bcc772d85c3c974f675b88e3e6e57"}, - {file = "mypy-1.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a64ee25f05fc2d3d8474985c58042b6759100a475f8237da1f4faf7fcd7e6309"}, - {file = "mypy-1.12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:faca7ab947c9f457a08dcb8d9a8664fd438080e002b0fa3e41b0535335edcf7f"}, - {file = "mypy-1.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:5bc81701d52cc8767005fdd2a08c19980de9ec61a25dbd2a937dfb1338a826f9"}, - {file = "mypy-1.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8462655b6694feb1c99e433ea905d46c478041a8b8f0c33f1dab00ae881b2164"}, - {file = "mypy-1.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:923ea66d282d8af9e0f9c21ffc6653643abb95b658c3a8a32dca1eff09c06475"}, - {file = "mypy-1.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1ebf9e796521f99d61864ed89d1fb2926d9ab6a5fab421e457cd9c7e4dd65aa9"}, - {file = "mypy-1.12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:e478601cc3e3fa9d6734d255a59c7a2e5c2934da4378f3dd1e3411ea8a248642"}, - {file = "mypy-1.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:c72861b7139a4f738344faa0e150834467521a3fba42dc98264e5aa9507dd601"}, - {file = "mypy-1.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:52b9e1492e47e1790360a43755fa04101a7ac72287b1a53ce817f35899ba0521"}, - {file = "mypy-1.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48d3e37dd7d9403e38fa86c46191de72705166d40b8c9f91a3de77350daa0893"}, - {file = "mypy-1.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2f106db5ccb60681b622ac768455743ee0e6a857724d648c9629a9bd2ac3f721"}, - {file = "mypy-1.12.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:233e11b3f73ee1f10efada2e6da0f555b2f3a5316e9d8a4a1224acc10e7181d3"}, - {file = "mypy-1.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:4ae8959c21abcf9d73aa6c74a313c45c0b5a188752bf37dace564e29f06e9c1b"}, - {file = "mypy-1.12.0-py3-none-any.whl", hash = "sha256:fd313226af375d52e1e36c383f39bf3836e1f192801116b31b090dfcd3ec5266"}, - {file = "mypy-1.12.0.tar.gz", hash = "sha256:65a22d87e757ccd95cbbf6f7e181e6caa87128255eb2b6be901bb71b26d8a99d"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1230048fec1380faf240be6385e709c8570604d2d27ec6ca7e573e3bc09c3735"}, + {file = "mypy-1.12.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:02dcfe270c6ea13338210908f8cadc8d31af0f04cee8ca996438fe6a97b4ec66"}, + {file = "mypy-1.12.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a5a437c9102a6a252d9e3a63edc191a3aed5f2fcb786d614722ee3f4472e33f6"}, + {file = "mypy-1.12.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:186e0c8346efc027ee1f9acf5ca734425fc4f7dc2b60144f0fbe27cc19dc7931"}, + {file = "mypy-1.12.1-cp311-cp311-win_amd64.whl", hash = "sha256:673ba1140a478b50e6d265c03391702fa11a5c5aff3f54d69a62a48da32cb811"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:9fb83a7be97c498176fb7486cafbb81decccaef1ac339d837c377b0ce3743a7f"}, + {file = "mypy-1.12.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:389e307e333879c571029d5b93932cf838b811d3f5395ed1ad05086b52148fb0"}, + {file = "mypy-1.12.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94b2048a95a21f7a9ebc9fbd075a4fcd310410d078aa0228dbbad7f71335e042"}, + {file = "mypy-1.12.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ee5932370ccf7ebf83f79d1c157a5929d7ea36313027b0d70a488493dc1b179"}, + {file = "mypy-1.12.1-cp312-cp312-win_amd64.whl", hash = "sha256:19bf51f87a295e7ab2894f1d8167622b063492d754e69c3c2fed6563268cb42a"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d34167d43613ffb1d6c6cdc0cc043bb106cac0aa5d6a4171f77ab92a3c758bcc"}, + {file = "mypy-1.12.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:427878aa54f2e2c5d8db31fa9010c599ed9f994b3b49e64ae9cd9990c40bd635"}, + {file = "mypy-1.12.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5fcde63ea2c9f69d6be859a1e6dd35955e87fa81de95bc240143cf00de1f7f81"}, + {file = "mypy-1.12.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d54d840f6c052929f4a3d2aab2066af0f45a020b085fe0e40d4583db52aab4e4"}, + {file = "mypy-1.12.1-cp313-cp313-win_amd64.whl", hash = "sha256:20db6eb1ca3d1de8ece00033b12f793f1ea9da767334b7e8c626a4872090cf02"}, + {file = "mypy-1.12.1-py3-none-any.whl", hash = "sha256:ce561a09e3bb9863ab77edf29ae3a50e65685ad74bba1431278185b7e5d5486e"}, + {file = "mypy-1.12.1.tar.gz", hash = "sha256:f5b3936f7a6d0e8280c9bdef94c7ce4847f5cdfc258fbb2c29a8c1711e8bb96d"}, ] [[package]] @@ -428,7 +551,7 @@ name = "packaging" version = "24.1" requires_python = ">=3.8" summary = "Core utilities for Python packages" -groups = ["default", "bootstrap", "dev"] +groups = ["default", "bootstrap", "dev", "docs"] files = [ {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, @@ -447,7 +570,7 @@ files = [ [[package]] name = "pdm" -version = "2.19.2" +version = "2.19.3" requires_python = ">=3.8" summary = "A modern Python package and dependency manager supporting the latest PEP standards" groups = ["default", "bootstrap"] @@ -477,8 +600,8 @@ dependencies = [ "virtualenv>=20", ] files = [ - {file = "pdm-2.19.2-py3-none-any.whl", hash = "sha256:42af4e0897b139656e003767e99c4f77014bf36d9a7b759d3e09b49ee5979143"}, - {file = "pdm-2.19.2.tar.gz", hash = "sha256:efb39264569181d0375536ef81c556648f16b540d429a53715730490a2283567"}, + {file = "pdm-2.19.3-py3-none-any.whl", hash = "sha256:80594e5d6167fb17ea724df09b68cdfe9c601ad7f218f1beea2c032b61bf30e9"}, + {file = "pdm-2.19.3.tar.gz", hash = "sha256:a9cc7f2078cd3b25ac645ffb5eca9d6b3d5dfcd788eaddfb6083432da71c97c2"}, ] [[package]] @@ -539,7 +662,7 @@ name = "pygments" version = "2.18.0" requires_python = ">=3.8" summary = "Pygments is a syntax highlighting package written in Python." -groups = ["default", "bootstrap"] +groups = ["default", "bootstrap", "docs"] files = [ {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, @@ -617,6 +740,23 @@ files = [ {file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"}, ] +[[package]] +name = "requests" +version = "2.32.3" +requires_python = ">=3.8" +summary = "Python HTTP for Humans." +groups = ["docs"] +dependencies = [ + "certifi>=2017.4.17", + "charset-normalizer<4,>=2", + "idna<4,>=2.5", + "urllib3<3,>=1.21.1", +] +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + [[package]] name = "resolvelib" version = "1.0.1" @@ -645,28 +785,28 @@ files = [ [[package]] name = "ruff" -version = "0.6.9" +version = "0.7.0" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." groups = ["dev"] files = [ - {file = "ruff-0.6.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:140d4b5c9f5fc7a7b074908a78ab8d384dd7f6510402267bc76c37195c02a7ec"}, - {file = "ruff-0.6.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:53fd8ca5e82bdee8da7f506d7b03a261f24cd43d090ea9db9a1dc59d9313914c"}, - {file = "ruff-0.6.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a67267654edc23c97335586774790cde402fb6bbdb3c2314f1fc087dee320bfa"}, - {file = "ruff-0.6.9-py3-none-win_amd64.whl", hash = "sha256:785d31851c1ae91f45b3d8fe23b8ae4b5170089021fbb42402d811135f0b7117"}, - {file = "ruff-0.6.9-py3-none-win_arm64.whl", hash = "sha256:a9641e31476d601f83cd602608739a0840e348bda93fec9f1ee816f8b6798b93"}, - {file = "ruff-0.6.9.tar.gz", hash = "sha256:b076ef717a8e5bc819514ee1d602bbdca5b4420ae13a9cf61a0c0a4f53a2baa2"}, + {file = "ruff-0.7.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:496494d350c7fdeb36ca4ef1c9f21d80d182423718782222c29b3e72b3512737"}, + {file = "ruff-0.7.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:214b88498684e20b6b2b8852c01d50f0651f3cc6118dfa113b4def9f14faaf06"}, + {file = "ruff-0.7.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d71672336e46b34e0c90a790afeac8a31954fd42872c1f6adaea1dff76fd44f9"}, + {file = "ruff-0.7.0-py3-none-win_amd64.whl", hash = "sha256:ff4aabfbaaba880e85d394603b9e75d32b0693152e16fa659a3064a85df7fce2"}, + {file = "ruff-0.7.0-py3-none-win_arm64.whl", hash = "sha256:10842f69c245e78d6adec7e1db0a7d9ddc2fff0621d730e61657b64fa36f207e"}, + {file = "ruff-0.7.0.tar.gz", hash = "sha256:47a86360cf62d9cd53ebfb0b5eb0e882193fc191c6d717e8bef4462bc3b9ea2b"}, ] [[package]] name = "setuptools" -version = "75.1.0" +version = "75.2.0" requires_python = ">=3.8" summary = "Easily download, build, install, upgrade, and uninstall Python packages" -groups = ["default", "git"] +groups = ["default"] files = [ - {file = "setuptools-75.1.0-py3-none-any.whl", hash = "sha256:35ab7fd3bcd95e6b7fd704e4a1539513edad446c097797f2985e0e4b960772f2"}, - {file = "setuptools-75.1.0.tar.gz", hash = "sha256:d59a21b17a275fb872a9c3dae73963160ae079f1049ed956880cd7c09b120538"}, + {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, + {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, ] [[package]] @@ -691,6 +831,16 @@ files = [ {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, ] +[[package]] +name = "snowballstemmer" +version = "2.2.0" +summary = "This package provides 29 stemmers for 28 languages generated from Snowball algorithms." +groups = ["docs"] +files = [ + {file = "snowballstemmer-2.2.0-py2.py3-none-any.whl", hash = "sha256:c8e1716e83cc398ae16824e5572ae04e0d9fc2c6b985fb0f900f5f0c96ecba1a"}, + {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, +] + [[package]] name = "socksio" version = "1.0.0" @@ -702,6 +852,127 @@ files = [ {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, ] +[[package]] +name = "soupsieve" +version = "2.6" +requires_python = ">=3.8" +summary = "A modern CSS selector implementation for Beautiful Soup." +groups = ["docs"] +files = [ + {file = "soupsieve-2.6-py3-none-any.whl", hash = "sha256:e72c4ff06e4fb6e4b5a9f0f55fe6e81514581fca1515028625d0f299c602ccc9"}, + {file = "soupsieve-2.6.tar.gz", hash = "sha256:e2e68417777af359ec65daac1057404a3c8a5455bb8abc36f1a9866ab1a51abb"}, +] + +[[package]] +name = "sphinx" +version = "8.1.3" +requires_python = ">=3.10" +summary = "Python documentation generator" +groups = ["docs"] +dependencies = [ + "Jinja2>=3.1", + "Pygments>=2.17", + "alabaster>=0.7.14", + "babel>=2.13", + "colorama>=0.4.6; sys_platform == \"win32\"", + "docutils<0.22,>=0.20", + "imagesize>=1.3", + "packaging>=23.0", + "requests>=2.30.0", + "snowballstemmer>=2.2", + "sphinxcontrib-applehelp>=1.0.7", + "sphinxcontrib-devhelp>=1.0.6", + "sphinxcontrib-htmlhelp>=2.0.6", + "sphinxcontrib-jsmath>=1.0.1", + "sphinxcontrib-qthelp>=1.0.6", + "sphinxcontrib-serializinghtml>=1.1.9", + "tomli>=2; python_version < \"3.11\"", +] +files = [ + {file = "sphinx-8.1.3-py3-none-any.whl", hash = "sha256:09719015511837b76bf6e03e42eb7595ac8c2e41eeb9c29c5b755c6b677992a2"}, + {file = "sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927"}, +] + +[[package]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +requires_python = ">=3.7" +summary = "A modern skeleton for Sphinx themes." +groups = ["docs"] +dependencies = [ + "sphinx>=4.0", +] +files = [ + {file = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl", hash = "sha256:eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b"}, + {file = "sphinx_basic_ng-1.0.0b2.tar.gz", hash = "sha256:9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9"}, +] + +[[package]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, +] + +[[package]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, +] + +[[package]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, +] + +[[package]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +requires_python = ">=3.5" +summary = "A sphinx extension which renders display math in HTML via JavaScript" +groups = ["docs"] +files = [ + {file = "sphinxcontrib-jsmath-1.0.1.tar.gz", hash = "sha256:a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8"}, + {file = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl", hash = "sha256:2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178"}, +] + +[[package]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, +] + +[[package]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +requires_python = ">=3.9" +summary = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" +groups = ["docs"] +files = [ + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, +] + [[package]] name = "tomlkit" version = "0.13.2" @@ -715,7 +986,7 @@ files = [ [[package]] name = "tox" -version = "4.21.2" +version = "4.23.0" requires_python = ">=3.8" summary = "tox is a generic virtualenv management and test command line tool" groups = ["dev"] @@ -733,8 +1004,8 @@ dependencies = [ "virtualenv>=20.26.6", ] files = [ - {file = "tox-4.21.2-py3-none-any.whl", hash = "sha256:13d996adcd792e7c82994b0e116d85efd84f0c6d185254d83d156f73f86b2038"}, - {file = "tox-4.21.2.tar.gz", hash = "sha256:49381ff102296753e378fa5ff30e42a35e695f149b4dbf8a2c49d15fdb5797b2"}, + {file = "tox-4.23.0-py3-none-any.whl", hash = "sha256:46da40afb660e46238c251280eb910bdaf00b390c7557c8e4bb611f422e9db12"}, + {file = "tox-4.23.0.tar.gz", hash = "sha256:a6bd7d54231d755348d3c3a7b450b5bf6563833716d1299a1619587a1b77a3bf"}, ] [[package]] @@ -823,7 +1094,7 @@ name = "urllib3" version = "2.2.3" requires_python = ">=3.8" summary = "HTTP library with thread-safe connection pooling, file post, and more." -groups = ["git"] +groups = ["docs"] files = [ {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, @@ -846,8 +1117,8 @@ files = [ [[package]] name = "virtualenv" -version = "20.26.6" -requires_python = ">=3.7" +version = "20.27.0" +requires_python = ">=3.8" summary = "Virtual Python Environment builder" groups = ["default", "bootstrap", "dev"] dependencies = [ @@ -857,8 +1128,8 @@ dependencies = [ "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, - {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, + {file = "virtualenv-20.27.0-py3-none-any.whl", hash = "sha256:44a72c29cceb0ee08f300b314848c86e57bf8d1f13107a5e671fb9274138d655"}, + {file = "virtualenv-20.27.0.tar.gz", hash = "sha256:2ca56a68ed615b8fe4326d11a0dca5dfbe8fd68510fb6c6349163bed3c15f2b2"}, ] [[package]] diff --git a/pyproject.toml b/pyproject.toml index 86a2fa2..f28a85e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,13 +59,13 @@ dev = [ # Uses exact pin for dev as lock file regeneration is sensitive to the exact uv version "uv==0.4.21", ] -git = [ - # Used by `misc/add_lock_metadata.py` to generate missing lock metadata files - "dulwich>=0.22.1", -] bootstrap = [ "pdm>=2.16.1", ] +docs = [ + "sphinx>=8.1.3", + "furo>=2024.8.6", +] [tool.pytest.ini_options] # Allow skipping slow tests for local testing diff --git a/tests/README.md b/tests/README.md index e61a163..44fad74 100644 --- a/tests/README.md +++ b/tests/README.md @@ -20,19 +20,19 @@ Running checks locally Static analysis: - tox -e lint,typecheck + tox -m static -Full test suite (py3.11 testing is also defined): +Full test suite (using the default target Python version): - tox -e py3.12 + tox -m test Skip slow tests (options after `--` are passed to `pytest`): - tox -e py3.12 -- -m "not slow" + tox -m test -- -m "not slow" Specific tests (options after `--` are passed to `pytest`): - tox -e py3.12 -- -k test_minimal_project + tox -m test -- -k test_minimal_project Refer to https://docs.pytest.org/en/6.2.x/usage.html#specifying-tests-selecting-tests for additional details on how to select which tests to run. @@ -47,14 +47,28 @@ Tests which take more than a few seconds to run should be marked as slow: def test_locking_and_publishing(self) -> None: ... +Marking tests with committed output files +----------------------------------------- + +Some tests work by comparing freshly generated outputs with expected outputs +committed to the repository (usually locked requirements files and expected +artifact metadata files). + +Tests which work this way must be marked as defined expected outputs: + + @pytest.mark.slow + def test_locking_and_publishing(self) -> None: + ... + Updating metadata and examining built artifacts ----------------------------------------------- -To generate a full local build to update metadata or to debug failures: +To generate a full local sample project build to help debug failures: $ cd /path/to/repo/src/ - $ ../.venv/bin/python -m venvstacks build --publish ../tests/sample_project/venvstacks.toml ~/path/to/output/folder + $ ../.venv/bin/python -m venvstacks build --publish \ + ../tests/sample_project/venvstacks.toml ~/path/to/output/folder (use `../.venv/Scripts/python` on Windows) @@ -66,9 +80,9 @@ built artifacts from the running test suite: VENVSTACKS_EXPORT_TEST_ARTIFACTS="~/path/to/output/folder" VENVSTACKS_FORCE_TEST_EXPORT=1 -The test suite can then be executed via `tox -e py3.11` or `tox -e py3.12` (the generated -metadata and artifacts should be identical regardless of which version of Python is used -to run `venvstacks`). +The test suite can then be executed via `tox --m test` (the generated metadata and +artifacts should be identical regardless of which version of Python is used to run +`venvstacks`). If the forced export env var is not set or is set to the empty string, artifacts will only be exported when test cases fail. Forcing exports can be useful for generating reference @@ -81,6 +95,8 @@ reference artifacts for debugging purposes. Debugging test suite failures related to artifact reproducibility ----------------------------------------------------------------- -`diffoscope` is a very helpful utility when trying to track down artifact discrepancies -(only available for non-Windows systems, but can be used in WSL or another Linux environment -to examine artifacts produced on Windows). +[`diffoscope`](https://pypi.org/project/diffoscope/) is a very helpful utility +when trying to track down artifact discrepancies. + +While it is only available for non-Windows systems, it can be used in WSL or +another non-Windows environment to examine artifacts produced on Windows. diff --git a/tox.ini b/tox.ini index 06a64ab..dc66148 100644 --- a/tox.ini +++ b/tox.ini @@ -28,11 +28,32 @@ commands = ruff check --exclude 'tests/sample_project' {posargs} src/ tests/ misc/ [testenv:typecheck] -groups = dev,git +groups = dev allowlist_externals = mypy commands = mypy --strict --exclude 'tests/sample_project' {posargs} src/ tests/ misc/ +[testenv:docs] +groups = [] +deps = -r docs/requirements.txt +allowlist_externals = sphinx-build +commands = + sphinx-build -b dirhtml {posargs} docs/ docs/_build + +[testenv:linkcheck] +groups = [] +deps = -r docs/requirements.txt +allowlist_externals = sphinx-build +commands = + sphinx-build -b linkcheck {posargs} docs/ docs/_build + +[testenv:regen-api-docs] +groups = [] +deps = -r docs/requirements.txt +allowlist_externals = docs/regen-api-docs.sh +commands = + docs/regen-api-docs.sh + [gh] python = 3.11 = py3.11