diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 950fb8ef2..6d4935bf1 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,13 +3,13 @@ name: Build on: push: branches: - - 'master' + - "master" paths-ignore: - - 'docs/**' - - 'mkdocs.yml' + - "docs/**" + - "mkdocs.yml" pull_request: branches: - - 'master' + - "master" workflow_dispatch: inputs: intergation-tests: @@ -56,20 +56,20 @@ jobs: path: frontend/build python-test: - needs: [ python-lint, frontend-build ] + needs: [python-lint, frontend-build] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ macos-latest, ubuntu-latest, windows-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] + os: [macos-latest, ubuntu-latest, windows-latest] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: astral-sh/setup-uv@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies - run: pip install -U '.[all]' -r requirements_dev.txt + run: uv sync --all-extras - name: Download frontend build uses: actions/download-artifact@v4 with: @@ -83,22 +83,26 @@ jobs: if [ "${{ matrix.os }}" != "macos-latest" ]; then RUNPOSTGRES="--runpostgres" fi - pytest src/tests --runui $RUNPOSTGRES + uv run pytest src/tests --runui $RUNPOSTGRES - name: Run pytest on Windows if: matrix.os == 'windows-latest' run: | - pytest src/tests --runui --runpostgres + uv run pytest src/tests --runui --runpostgres update-get-dstack: if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - needs: [ python-test ] + needs: [python-test] runs-on: ubuntu-latest env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} steps: + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - run: | VERSION=$((${{ github.run_number }} + ${{ env.BUILD_INCREMENT }})) echo $VERSION | aws s3 cp - s3://get-dstack/stgn-cli/latest-version --acl public-read @@ -181,8 +185,12 @@ jobs: needs: [runner-compile] runs-on: ubuntu-latest steps: + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - name: Download Runner uses: actions/download-artifact@v4 with: @@ -201,24 +209,24 @@ jobs: generate-json-schema: if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository - needs: [ python-test ] + needs: [python-test] env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - name: Install dstack - run: pip install . + run: uv sync - name: Generate json schema run: | - python -c "from dstack._internal.core.models.configurations import DstackConfiguration; print(DstackConfiguration.schema_json(indent=2))" > configuration.json - python -c "from dstack._internal.core.models.profiles import ProfilesConfig; print(ProfilesConfig.schema_json(indent=2))" > profiles.json + uv run python -c "from dstack._internal.core.models.configurations import DstackConfiguration; print(DstackConfiguration.schema_json(indent=2))" > configuration.json + uv run python -c "from dstack._internal.core.models.profiles import ProfilesConfig; print(ProfilesConfig.schema_json(indent=2))" > profiles.json - name: Upload json schema to S3 run: | VERSION=$((${{ github.run_number }} + ${{ env.BUILD_INCREMENT }})) @@ -235,20 +243,18 @@ jobs: working-directory: gateway steps: - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 + - name: Set up uv + uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install AWS - run: pip install awscli - - name: Install dependencies - run: pip install wheel build + run: uv tool install awscli - name: Compute version run: echo VERSION=$((${{ github.run_number }} + ${{ env.BUILD_INCREMENT }})) > $GITHUB_ENV - name: Build package run: | echo "__version__ = \"${{ env.VERSION }}\"" > src/dstack/gateway/version.py - python -m build . + uv build - name: Upload to S3 env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -257,23 +263,24 @@ jobs: WHEEL=dstack_gateway-${{ env.VERSION }}-py3-none-any.whl aws s3 cp dist/$WHEEL "s3://dstack-gateway-downloads/stgn/$WHEEL" echo "${{ env.VERSION }}" | aws s3 cp - "s3://dstack-gateway-downloads/stgn/latest-version" - + docs-build: # Skip for PRs from forks since mkdocs-material-insiders is not available in forks if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install dstack run: | - pip install -e .[server] + uv sync --extra server + # Move these deps into an extra and install that way - name: Build run: | - pip install pillow cairosvg + uv pip install pillow cairosvg sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev - pip install mkdocs-material "mkdocs-material[imaging]" mkdocs-material-extensions mkdocs-redirects mkdocs-gen-files "mkdocstrings[python]" mkdocs-render-swagger-plugin --upgrade - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git - mkdocs build -s + uv pip install mkdocs-material "mkdocs-material[imaging]" mkdocs-material-extensions mkdocs-redirects mkdocs-gen-files "mkdocstrings[python]" mkdocs-render-swagger-plugin --upgrade + uv pip install git+https://${{ secrets.GH_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git + uv mkdocs build -s diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index b6ba71d78..ecf412624 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -34,7 +34,7 @@ on: env: PACKER_VERSION: "1.9.2" - BUILD_PREFIX: ${{ inputs.staging && format('stgn-{0}-', github.run_number) || '' }} # staging ? prefix : '' + BUILD_PREFIX: ${{ inputs.staging && format('stgn-{0}-', github.run_number) || '' }} # staging ? prefix : '' jobs: build-docker: @@ -45,23 +45,23 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] + python: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - name: Checkout repository - uses: actions/checkout@v4 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - name: Login to DockerHub - uses: docker/login-action@v3 - with: - username: ${{ secrets.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - - name: Build and upload to DockerHub - run: | - docker buildx build --platform linux/amd64 --build-arg PYTHON=${{ matrix.python }} --push --provenance=false --tag dstackai/base:py${{ matrix.python }}-${{ inputs.image_version }}-cuda-12.1 -f base/Dockerfile . - docker buildx build --platform linux/amd64 --build-arg PYTHON=${{ matrix.python }} --build-arg VERSION=${{ inputs.image_version }} --push --provenance=false --tag dstackai/base:py${{ matrix.python }}-${{ inputs.image_version }}-cuda-12.1-devel -f base/devel.Dockerfile . + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Login to DockerHub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - name: Build and upload to DockerHub + run: | + docker buildx build --platform linux/amd64 --build-arg PYTHON=${{ matrix.python }} --push --provenance=false --tag dstackai/base:py${{ matrix.python }}-${{ inputs.image_version }}-cuda-12.1 -f base/Dockerfile . + docker buildx build --platform linux/amd64 --build-arg PYTHON=${{ matrix.python }} --build-arg VERSION=${{ inputs.image_version }} --push --provenance=false --tag dstackai/base:py${{ matrix.python }}-${{ inputs.image_version }}-cuda-12.1-devel -f base/devel.Dockerfile . build-aws-images: needs: build-docker @@ -75,7 +75,7 @@ jobs: AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} strategy: matrix: - variant: [ "", "-cuda" ] + variant: ["", "-cuda"] steps: - uses: actions/checkout@v4 - name: Download packer @@ -87,7 +87,7 @@ jobs: run: | ./packer build -var-file=versions.json $PROD_VARS -var image_version=${{ inputs.image_version }} -var build_prefix=$BUILD_PREFIX aws-image${{ matrix.variant }}.json env: - PROD_VARS: ${{ !inputs.staging && '-var-file=aws-vars-prod.json' || '' }} # production ? var-file : '' + PROD_VARS: ${{ !inputs.staging && '-var-file=aws-vars-prod.json' || '' }} # production ? var-file : '' build-azure-images: needs: build-docker @@ -104,7 +104,7 @@ jobs: VERSION: ${{ github.run_number }} strategy: matrix: - variant: [ "", "-cuda", "-grid" ] + variant: ["", "-cuda", "-grid"] steps: - uses: actions/checkout@v4 - uses: Azure/login@v2 @@ -135,17 +135,17 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - variant: [ "", "-cuda" ] + variant: ["", "-cuda"] permissions: - contents: 'read' - id-token: 'write' + contents: "read" + id-token: "write" steps: - uses: actions/checkout@v4 - name: Authenticate to Google Cloud uses: google-github-actions/auth@v2 with: - workload_identity_provider: 'projects/531508670106/locations/global/workloadIdentityPools/github-identity-pool/providers/github-id-provider' - service_account: 'github-actions@dstack.iam.gserviceaccount.com' + workload_identity_provider: "projects/531508670106/locations/global/workloadIdentityPools/github-identity-pool/providers/github-id-provider" + service_account: "github-actions@dstack.iam.gserviceaccount.com" create_credentials_file: true - name: Set up Cloud SDK uses: google-github-actions/setup-gcloud@v2 @@ -175,7 +175,7 @@ jobs: OCI_REGION: eu-frankfurt-1 strategy: matrix: - variant: [ "", "-cuda" ] + variant: ["", "-cuda"] steps: - uses: actions/checkout@v4 - name: Setup OCI config @@ -211,23 +211,23 @@ jobs: -var oci_subnet_ocid=$OCI_SUBNET \ -var oci_availability_domain=$OCI_AVAILABILITY_DOMAIN \ oci-image${{ matrix.variant }}.json - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v5 with: - python-version: '3.12' + python-version: "3.12" - name: Install dependencies for publishing run: | - pip install .[oci] + uv sync --extra oci - name: Copy image to target regions if: ${{ !inputs.staging }} run: | - python scripts/oci_image_tools.py copy \ + uv run scripts/oci_image_tools.py copy \ --image ${BUILD_PREFIX}dstack${{ matrix.variant }}-${{ inputs.image_version }} \ --from $OCI_REGION \ --compartment $OCI_COMPARTMENT - name: Publish image in OCI Marketplace if: ${{ !inputs.staging }} run: | - python scripts/oci_image_tools.py publish \ + uv run scripts/oci_image_tools.py publish \ --image ${BUILD_PREFIX}dstack${{ matrix.variant }}-${{ inputs.image_version }} \ --compartment $OCI_COMPARTMENT \ --version ${{ inputs.image_version }} \ diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index 1c9ae5f1b..02c238fbe 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -11,23 +11,23 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install dstack run: | if [ -n "${{ inputs.release_tag }}" ]; then - pip install "dstack[server]==${{ inputs.release_tag }}" + uv pip install "dstack[server]==${{ inputs.release_tag }}" else - pip install -e .[server] + uv sync --extra server fi - name: Build run: | - pip install pillow cairosvg + uv pip install pillow cairosvg sudo apt-get install -y libcairo2-dev libfreetype6-dev libffi-dev libjpeg-dev libpng-dev libz-dev - pip install mkdocs-material "mkdocs-material[imaging]" mkdocs-material-extensions mkdocs-redirects mkdocs-gen-files "mkdocstrings[python]" mkdocs-render-swagger-plugin --upgrade - pip install git+https://${{ secrets.GH_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git - mkdocs build -s + uv pip install mkdocs-material "mkdocs-material[imaging]" mkdocs-material-extensions mkdocs-redirects mkdocs-gen-files "mkdocstrings[python]" mkdocs-render-swagger-plugin --upgrade + uv pip install git+https://${{ secrets.GH_TOKEN }}@github.com/squidfunk/mkdocs-material-insiders.git + uv mkdocs build -s - name: Deploy uses: JamesIves/github-pages-deploy-action@v4.6.4 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 35a59df0c..3f2710647 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -47,20 +47,20 @@ jobs: path: frontend/build python-test: - needs: [ python-lint, frontend-build ] + needs: [python-lint, frontend-build] runs-on: ${{ matrix.os }} strategy: matrix: - os: [ macos-latest, ubuntu-latest, windows-latest ] - python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ] + os: [macos-latest, ubuntu-latest, windows-latest] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: astral-sh/setup-uv@v5 with: python-version: ${{ matrix.python-version }} - name: Install dependencies - run: pip install -U '.[all]' -r requirements_dev.txt + run: uv sync --all-extras - name: Download frontend build uses: actions/download-artifact@v4 with: @@ -74,11 +74,11 @@ jobs: if [ "${{ matrix.os }}" != "macos-latest" ]; then RUNPOSTGRES="--runpostgres" fi - pytest src/tests --runui $RUNPOSTGRES + uv run pytest src/tests --runui $RUNPOSTGRES - name: Run pytest on Windows if: matrix.os == 'windows-latest' run: | - pytest src/tests --runui --runpostgres + uv run pytest src/tests --runui --runpostgres runner-test: defaults: @@ -150,14 +150,12 @@ jobs: working-directory: gateway steps: - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 + - name: Set up uv + uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install AWS - run: pip install awscli - - name: Install dependencies - run: pip install wheel build + run: uv tool install awscli - name: Store version run: echo VERSION=${GITHUB_REF#refs/tags/} > $GITHUB_ENV - name: Build package @@ -168,7 +166,7 @@ jobs: "s|@ https://github.com/dstackai/dstack/archive/refs/heads/master.zip|== ${{ env.VERSION }}|" \ pyproject.toml diff pyproject.toml pyproject.toml.old > /dev/null && echo "Could not set version" && exit 1 - python -m build . + uv build - name: Upload to S3 env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} @@ -182,8 +180,12 @@ jobs: needs: [runner-compile, gateway-build, python-test] runs-on: ubuntu-latest steps: + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - name: Download Runner uses: actions/download-artifact@v4 with: @@ -201,15 +203,15 @@ jobs: aws s3 cp . "s3://dstack-runner-downloads/latest/binaries/" --recursive --exclude "*" --include "dstack-*" --acl public-read pypi-upload: - needs: [ python-test, runner-upload ] + needs: [python-test, runner-upload] runs-on: ubuntu-latest outputs: LATEST: ${{ steps.set_latest.outputs.LATEST }} name: Set latest variable steps: - uses: actions/checkout@v4 - - name: Set up Python 3.11 - uses: actions/setup-python@v5 + - name: Set up uv + uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Download frontend build @@ -217,10 +219,6 @@ jobs: with: name: frontend-build path: src/dstack/_internal/server/statics - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install wheel twine packaging - name: Set output id: set_latest run: | @@ -235,24 +233,28 @@ jobs: echo "__is_release__ = True" >> src/dstack/version.py echo $BASE_IMAGE >> src/dstack/version.py cp README.md src - python setup.py sdist bdist_wheel -v - python -m twine upload --repository pypi --username ${{ secrets.PYPI_USERNAME }} --password ${{ secrets.PYPI_PASSWORD }} dist/* + uv build + uv publish --username ${{ secrets.PYPI_USERNAME }} --password ${{ secrets.PYPI_PASSWORD }} update-get-dstack-tag: - needs: [ pypi-upload ] + needs: [pypi-upload] runs-on: ubuntu-latest env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} steps: + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - run: | VERSION=${GITHUB_REF#refs/tags/} echo $VERSION | aws s3 cp - s3://get-dstack/cli/latest-version --acl public-read server-docker-upload: - needs: [ pypi-upload ] + needs: [pypi-upload] defaults: run: working-directory: docker/server @@ -289,24 +291,24 @@ jobs: readme-filepath: ./docker/server/README.md generate-json-schema: - needs: [ pypi-upload ] + needs: [pypi-upload] env: AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: astral-sh/setup-uv@v5 with: python-version: 3.11 - name: Install AWS - run: pip install awscli + run: uv tool install awscli - name: Install dstack - run: pip install . + run: uv sync - name: Generate json schema run: | - python -c "from dstack._internal.core.models.configurations import DstackConfiguration; print(DstackConfiguration.schema_json(indent=2))" > configuration.json - python -c "from dstack._internal.core.models.profiles import ProfilesConfig; print(ProfilesConfig.schema_json(indent=2))" > profiles.json + uv run python -c "from dstack._internal.core.models.configurations import DstackConfiguration; print(DstackConfiguration.schema_json(indent=2))" > configuration.json + uv run python -c "from dstack._internal.core.models.profiles import ProfilesConfig; print(ProfilesConfig.schema_json(indent=2))" > profiles.json - name: Upload json schema to S3 run: | VERSION=${GITHUB_REF#refs/tags/} diff --git a/.gitignore b/.gitignore index 344e57de0..0f577dce9 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ build/ .fleet .env .aider* +uv.lock diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 94f85b103..3b65f0e94 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,8 +28,8 @@ If you make a non-trivial change to `dstack`, we recommend you learn about `dsta We use [`ruff`](https://docs.astral.sh/ruff/) to format Python code and to sort Python imports. Before committing your changes, run: -1. `ruff check --fix` -2. `ruff format` +1. `uv run ruff check --fix` +2. `uv run ruff format` > There are also helper pre-commits installed for [`ruff`](https://docs.astral.sh/ruff/integrations/#pre-commit) that make commits fail if the code is not formatted or the imports are not sorted. They also change the code as required so that you can review the changes and commit again. @@ -40,14 +40,14 @@ To run Python tests, first ensure you've install dev dependencies as described i Then you can do: ```shell -pytest src/tests +uv run pytest src/tests ``` (Optionally) By default, tests run against SQLite. Use the `--runpostgres` flag to run the tests against Postgres as well: ```shell -pytest src/tests --runpostgres +uv run pytest src/tests --runpostgres ``` ## Add a new backend diff --git a/contributing/DEVELOPMENT.md b/contributing/DEVELOPMENT.md index 935c1abd2..775a0691e 100644 --- a/contributing/DEVELOPMENT.md +++ b/contributing/DEVELOPMENT.md @@ -6,32 +6,31 @@ git clone https://github.com/dstackai/dstack cd dstack ``` - -## 2. (Recommended) Create a virtual environment: -```shell -python3 -m venv venv -source venv/bin/activate -``` - -## 3. Install `dstack` in editable mode: +## 2. Install uv: + +https://docs.astral.sh/uv/getting-started/installation ```shell -pip install -e '.[all]' +curl -LsSf https://astral.sh/uv/install.sh | sh ``` - -## 4. Install dev dependencies: + +## 3. Install `dstack` with all extras and dev dependencies: ```shell -pip install -r requirements_dev.txt +uv sync --all-extras ``` - -## 5. (Recommended) Install pre-commits: + +`dstack` will be installed into the project's `.venv` in editable mode and can be run with `uv run dstack`. + +Alternatively, if you want to manage virtual environments by yourself, you can install `dstack` into the activated virtual environment with `uv sync --all-extras --active`. + +## 4. (Recommended) Install pre-commits: ```shell -pre-commit install +uv run pre-commit install ``` -## 6. Frontend +## 5. Frontend See [FRONTEND.md](FRONTEND.md) for the details on how to build and develop the frontend. diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..627990eba --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,169 @@ +[project] +name = "dstack" +dynamic = ["version", "readme"] +authors = [{ name = "Andrey Cheptsov", email = "andrey@dstack.ai" }] +description = "dstack is an open-source orchestration engine for running AI workloads on any cloud or on-premises." +requires-python = ">=3.9" +classifiers = [ + "Development Status :: 4 - Beta", + "Topic :: Scientific/Engineering :: Artificial Intelligence", + "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", + "Programming Language :: Python :: 3", +] +dependencies = [ + "pyyaml", + "requests", + "typing-extensions>=4.0.0", + "cryptography", + "packaging", + "python-dateutil", + "cachetools", + "gitpython", + "jsonschema", + "paramiko>=3.2.0", + "cursor", + "rich", + "rich-argparse", + "tqdm", + "simple-term-menu", + "pydantic>=1.10.10,<2.0.0", + "pydantic-duality>=1.2.4", + "websocket-client", + "python-multipart>=0.0.16", + "filelock", + "psutil", + "gpuhunt>=0.1.2,<0.2.0", + "argcomplete>=3.5.0", +] + +[project.urls] +Homepage = "https://dstack.ai" +Source = "https://github.com/dstackai/dstack" +Documentation = "https://dstack.ai/docs" +Issues = "https://github.com/dstackai/dstack/issues" +Changelog = "https://github.com/dstackai/dstack/releases" +Discord = "https://discord.gg/u8SmfwPpMd" + +[build-system] +requires = ["hatchling", "hatch-vcs", "hatch-fancy-pypi-readme"] +build-backend = "hatchling.build" + +[project.scripts] +dstack = "dstack._internal.cli.main:main" + +[tool.hatch.version] +source = "vcs" + +[tool.hatch.build.targets.wheel.shared-data] +"src/dstack/_internal/proxy/gateway/resources" = "dstack/_internal/proxy/gateway/resources" +"src/dstack/_internal/server/statics" = "dstack/_internal/server/statics" + +[tool.hatch.metadata.hooks.fancy-pypi-readme] +content-type = "text/markdown" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.fragments]] +path = "README.md" + +[[tool.hatch.metadata.hooks.fancy-pypi-readme.substitutions]] +pattern = '\s*|]*>\s*|\s*|]*>\s*|\s*|### Demo\s*' +replacement = '' +ignore-case = true + +[dependency-groups] +dev = [ + "build>=1.2.2.post1", + "httpx>=0.28.1", + "pre-commit>=4.2.0", + "pytest-asyncio>=0.23.8", + "pytest-httpbin>=2.1.0", + "httpbin>=0.10.2", # indirect to make compatible with Werkzeug 3 + "pytest~=7.2", + "pytest-socket>=0.7.0", + "requests-mock>=1.12.1", + "openai>=1.68.2", + "freezegun>=1.5.1", + "ruff>=0.11.2", + "testcontainers>=4.9.2", +] + +[project.optional-dependencies] +gateway = [ + "fastapi", + "starlette>=0.26.0", + "uvicorn", + "aiorwlock", + "aiocache", + "httpx", + "jinja2", +] +server = [ + "fastapi", + "starlette>=0.26.0", + "uvicorn", + "aiorwlock", + "aiocache", + "httpx", + "jinja2", + "watchfiles", + "sqlalchemy[asyncio]>=2.0.0", + "sqlalchemy_utils>=0.40.0", + "alembic>=1.10.2", + "apscheduler<4", + "aiosqlite", + "docker>=6.0.0", + "python-dxf==12.1.0", + "sentry-sdk[fastapi]", + "alembic-postgresql-enum", + "asyncpg", + "python-json-logger>=3.1.0", + "prometheus-client", + "grpcio>=1.50", +] +aws = [ + "boto3", + "botocore", + "dstack[server]", +] +azure = [ + "azure-identity>=1.12.0", + "azure-mgmt-subscription>=3.1.1", + "azure-mgmt-compute>=29.1.0", + "azure-mgmt-network>=23.0.0,<28.0.0", + "azure-mgmt-resource>=22.0.0", + "azure-mgmt-authorization>=3.0.0", + "dstack[server]", +] +gcp = [ + "google-auth>=2.3.0", + "google-cloud-storage>=2.0.0", + "google-cloud-compute>=1.5.0", + "google-cloud-logging>=2.0.0", + "google-api-python-client>=2.80.0", + "google-cloud-billing>=1.11.0", + "google-cloud-tpu>=1.18.3", + "dstack[server]", +] +datacrunch = [ + "datacrunch", + "dstack[server]", +] +kubernetes = [ + "kubernetes", + "dstack[server]", +] +lambda = [ + "boto3", + "botocore", + "dstack[server]", +] +oci = [ + "oci", + "dstack[server]", +] +nebius = [ + "nebius>=0.2.19,<0.3; python_version >= '3.10'", + "dstack[server]", +] +all = [ + "dstack[gateway,server,aws,azure,gcp,datacrunch,kubernetes,lambda,nebius,oci]", +] diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 78ad4b818..000000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,12 +0,0 @@ -build~=1.2 # For building dstack-gateway wheels -pre-commit -httpx>=0.23 -pytest~=7.2 -pytest-asyncio>=0.21 -pytest-httpbin==2.1.0 -pytest-socket>=0.7.0 -requests-mock>=1.12.1 -openai>=1.53.0,<2.0.0 -freezegun>=1.2.0 -ruff==0.5.3 # Should match .pre-commit-config.yaml -testcontainers # testcontainers<4 may not work with asyncpg diff --git a/setup.py b/setup.py deleted file mode 100644 index 5da9fe3cb..000000000 --- a/setup.py +++ /dev/null @@ -1,180 +0,0 @@ -import re -import sys -from pathlib import Path - -from setuptools import find_packages, setup - -project_dir = Path(__file__).parent - - -def get_version(): - text = (project_dir / "src" / "dstack" / "version.py").read_text() - match = re.compile(r"__version__\s*=\s*\"?([^\n\"]+)\"?.*").match(text) - if match: - if match.group(1) != "None": - return match.group(1) - else: - return None - else: - sys.exit("Can't parse version.py") - - -def get_long_description(): - return re.sub( - r"\s*|]*>\s*|\s*|]*>\s*|\s*|### Demo\s*", - "", - open(project_dir / "README.md").read(), - ) - - -BASE_DEPS = [ - "pyyaml", - "requests", - "typing-extensions>=4.0.0", - "cryptography", - "packaging", - "python-dateutil", - "cachetools", - "gitpython", - "jsonschema", - "paramiko>=3.2.0", - "cursor", - "rich", - "rich-argparse", - "tqdm", - "simple-term-menu", - "pydantic>=1.10.10,<2.0.0", - "pydantic-duality>=1.2.4", - "websocket-client", - "python-multipart>=0.0.16", - "filelock", - "psutil", - "gpuhunt>=0.1.2,<0.2.0", - "argcomplete>=3.5.0", -] - -GATEWAY_AND_SERVER_COMMON_DEPS = [ - "fastapi", - "starlette>=0.26.0", - "uvicorn", - "aiorwlock", - "aiocache", - "httpx", - "jinja2", -] - -SERVER_DEPS = GATEWAY_AND_SERVER_COMMON_DEPS + [ - "watchfiles", - "sqlalchemy[asyncio]>=2.0.0", - "sqlalchemy_utils>=0.40.0", - "alembic>=1.10.2", - "apscheduler<4", - "aiosqlite", - "docker>=6.0.0", - "python-dxf==12.1.0", - "sentry-sdk[fastapi]", - "alembic-postgresql-enum", - "asyncpg", - "python-json-logger>=3.1.0", - "prometheus-client", - "grpcio>=1.50", # indirect -] - -AWS_DEPS = [ - "boto3", - "botocore", -] - -AZURE_DEPS = [ - "azure-identity>=1.12.0", - "azure-mgmt-subscription>=3.1.1", - "azure-mgmt-compute>=29.1.0", - "azure-mgmt-network>=23.0.0,<28.0.0", - "azure-mgmt-resource>=22.0.0", - "azure-mgmt-authorization>=3.0.0", -] - -GCP_DEPS = [ - "google-auth>=2.3.0", # indirect - "google-cloud-storage>=2.0.0", - "google-cloud-compute>=1.5.0", - "google-cloud-logging>=2.0.0", - "google-api-python-client>=2.80.0", - "google-cloud-billing>=1.11.0", - "google-cloud-tpu>=1.18.3", -] - -DATACRUNCH_DEPS = ["datacrunch"] - -KUBERNETES_DEPS = ["kubernetes"] - -LAMBDA_DEPS = AWS_DEPS - -# Nebius requires Python 3.10. On 3.9: -# `pip install dstack[nebius]` is expected to fail -# `pip install dstack[all]` is expected to ignore Nebius -NEBIUS_DEPS = ["nebius>=0.2.19,<0.3"] -MAYBE_NEBIUS_DEPS = ['nebius>=0.2.19,<0.3; python_version>="3.10"'] - -OCI_DEPS = ["oci"] - -ALL_DEPS = ( - SERVER_DEPS - + AWS_DEPS - + AZURE_DEPS - + GCP_DEPS - + DATACRUNCH_DEPS - + KUBERNETES_DEPS - + MAYBE_NEBIUS_DEPS - + OCI_DEPS -) - -setup( - name="dstack", - version=get_version(), - author="Andrey Cheptsov", - author_email="andrey@dstack.ai", - package_dir={"": "src"}, - packages=find_packages("src"), - package_data={ - "dstack._internal.proxy.gateway": ["resources/**/*"], - "dstack._internal.server": ["statics/**/*"], - }, - include_package_data=True, - scripts=[], - entry_points={ - "console_scripts": ["dstack=dstack._internal.cli.main:main"], - }, - url="https://dstack.ai", - project_urls={ - "Source": "https://github.com/dstackai/dstack", - "Docs": "https://dstack.ai/docs", - "Issues": "https://github.com/dstackai/dstack/issues", - "Changelog": "https://github.com/dstackai/dstack/releases", - "Discord": "https://discord.gg/u8SmfwPpMd", - }, - description="dstack is an open-source orchestration engine for running AI workloads on any cloud or on-premises.", - long_description=get_long_description(), - long_description_content_type="text/markdown", - python_requires=">=3.9", - install_requires=BASE_DEPS, - extras_require={ - "all": ALL_DEPS, - "gateway": GATEWAY_AND_SERVER_COMMON_DEPS, - "server": SERVER_DEPS, - "aws": SERVER_DEPS + AWS_DEPS, - "azure": SERVER_DEPS + AZURE_DEPS, - "datacrunch": SERVER_DEPS + DATACRUNCH_DEPS, - "gcp": SERVER_DEPS + GCP_DEPS, - "kubernetes": SERVER_DEPS + KUBERNETES_DEPS, - "lambda": SERVER_DEPS + LAMBDA_DEPS, - "nebius": SERVER_DEPS + NEBIUS_DEPS, - "oci": SERVER_DEPS + OCI_DEPS, - }, - classifiers=[ - "Development Status :: 4 - Beta", - "Topic :: Scientific/Engineering :: Artificial Intelligence", - "License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)", - "Programming Language :: Python :: 3", - ], -)